@sodax/dapp-kit 2.0.0-rc.2 → 2.0.0-rc.20

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.
Files changed (129) hide show
  1. package/README.md +29 -74
  2. package/dist/index.d.ts +780 -58
  3. package/dist/index.mjs +841 -143
  4. package/package.json +31 -19
  5. package/src/hooks/_mutationContract.test.ts +15 -2
  6. package/src/hooks/backend/index.ts +1 -5
  7. package/src/hooks/bitcoin/index.ts +2 -0
  8. package/src/hooks/bitcoin/resolveBtcReadAddress.test.ts +54 -0
  9. package/src/hooks/bitcoin/resolveBtcReadAddress.ts +21 -0
  10. package/src/hooks/bitcoin/useBitcoinTradingSetup.ts +45 -0
  11. package/src/hooks/bitcoin/useEnsureRadfiAccessToken.ts +57 -0
  12. package/src/hooks/bitcoin/useFundTradingWallet.ts +1 -1
  13. package/src/hooks/bitcoin/useRadfiAuth.ts +2 -2
  14. package/src/hooks/bitcoin/useRadfiWithdraw.ts +2 -2
  15. package/src/hooks/bitcoin/useRenewUtxos.ts +2 -2
  16. package/src/hooks/bitcoin/useTradingWallet.ts +1 -1
  17. package/src/hooks/index.ts +2 -0
  18. package/src/hooks/leverageYield/index.ts +9 -0
  19. package/src/hooks/leverageYield/useLeverageYieldDeposit.ts +40 -0
  20. package/src/hooks/leverageYield/useLeverageYieldEffectiveApr.ts +42 -0
  21. package/src/hooks/leverageYield/useLeverageYieldNotifySolver.ts +34 -0
  22. package/src/hooks/leverageYield/useLeverageYieldPosition.ts +40 -0
  23. package/src/hooks/leverageYield/useLeverageYieldPreviewRedeem.ts +43 -0
  24. package/src/hooks/leverageYield/useLeverageYieldShareBalances.ts +74 -0
  25. package/src/hooks/leverageYield/useLeverageYieldTotalAssets.ts +36 -0
  26. package/src/hooks/leverageYield/useLeverageYieldVaultSwap.ts +50 -0
  27. package/src/hooks/leverageYield/useLeverageYieldWithdraw.ts +40 -0
  28. package/src/hooks/mm/useATokensBalances.ts +7 -1
  29. package/src/hooks/mm/useUserFormattedSummary.ts +5 -1
  30. package/src/hooks/mm/useUserReservesData.ts +5 -1
  31. package/src/hooks/partner/index.ts +4 -0
  32. package/src/hooks/partner/useFeeClaimWithdraw.ts +88 -0
  33. package/src/hooks/partner/useGetIntentDetails.ts +39 -0
  34. package/src/hooks/partner/useGetUserIntent.ts +35 -0
  35. package/src/hooks/partner/usePartnerCancelIntent.ts +52 -0
  36. package/src/hooks/shared/index.ts +4 -0
  37. package/src/hooks/shared/isUserRejectedError.test.ts +42 -0
  38. package/src/hooks/shared/isUserRejectedError.ts +30 -0
  39. package/src/hooks/shared/useGetUserHubWalletAddress.ts +5 -1
  40. package/src/hooks/shared/useNearStorageCheck.ts +45 -0
  41. package/src/hooks/shared/useNearStorageGate.ts +60 -0
  42. package/src/hooks/shared/useRegisterNearStorage.ts +46 -0
  43. package/src/hooks/swapsApi/index.ts +41 -0
  44. package/src/hooks/swapsApi/isTerminalSwapIntentStatus.test.ts +24 -0
  45. package/src/hooks/swapsApi/isTerminalSwapIntentStatus.ts +11 -0
  46. package/src/hooks/swapsApi/useSwapsApiAllowance.ts +40 -0
  47. package/src/hooks/swapsApi/useSwapsApiApprove.ts +42 -0
  48. package/src/hooks/swapsApi/useSwapsApiCancelIntent.ts +41 -0
  49. package/src/hooks/swapsApi/useSwapsApiCreateIntent.ts +41 -0
  50. package/src/hooks/swapsApi/useSwapsApiCreateLimitOrder.ts +41 -0
  51. package/src/hooks/swapsApi/useSwapsApiDeadline.ts +36 -0
  52. package/src/hooks/swapsApi/useSwapsApiEstimateGas.ts +40 -0
  53. package/src/hooks/swapsApi/useSwapsApiFilledIntent.ts +41 -0
  54. package/src/hooks/swapsApi/useSwapsApiIntent.ts +40 -0
  55. package/src/hooks/swapsApi/useSwapsApiIntentExtraData.ts +41 -0
  56. package/src/hooks/swapsApi/useSwapsApiIntentHash.ts +40 -0
  57. package/src/hooks/swapsApi/useSwapsApiIntentPacket.ts +43 -0
  58. package/src/hooks/swapsApi/useSwapsApiPartnerFee.ts +40 -0
  59. package/src/hooks/swapsApi/useSwapsApiQuote.ts +55 -0
  60. package/src/hooks/swapsApi/useSwapsApiSolverFee.ts +40 -0
  61. package/src/hooks/swapsApi/useSwapsApiStatus.ts +45 -0
  62. package/src/hooks/swapsApi/useSwapsApiSubmitIntent.ts +43 -0
  63. package/src/hooks/{backend/useBackendSubmitSwapTx.ts → swapsApi/useSwapsApiSubmitTx.ts} +16 -17
  64. package/src/hooks/swapsApi/useSwapsApiSubmitTxStatus.ts +55 -0
  65. package/src/hooks/swapsApi/useSwapsApiTokens.ts +34 -0
  66. package/src/hooks/swapsApi/useSwapsApiTokensByChain.ts +40 -0
  67. package/src/providers/SodaxProvider.tsx +17 -14
  68. package/src/utils/index.ts +1 -0
  69. package/src/utils/nearStorageGate.test.ts +46 -0
  70. package/src/utils/nearStorageGate.ts +39 -0
  71. package/ai-exported/AGENTS.md +0 -134
  72. package/ai-exported/integration/README.md +0 -49
  73. package/ai-exported/integration/ai-rules.md +0 -79
  74. package/ai-exported/integration/architecture.md +0 -274
  75. package/ai-exported/integration/features/README.md +0 -29
  76. package/ai-exported/integration/features/auxiliary-services.md +0 -169
  77. package/ai-exported/integration/features/bitcoin.md +0 -87
  78. package/ai-exported/integration/features/bridge.md +0 -91
  79. package/ai-exported/integration/features/dex.md +0 -152
  80. package/ai-exported/integration/features/migration.md +0 -118
  81. package/ai-exported/integration/features/money-market.md +0 -116
  82. package/ai-exported/integration/features/staking.md +0 -123
  83. package/ai-exported/integration/features/swap.md +0 -101
  84. package/ai-exported/integration/quickstart.md +0 -187
  85. package/ai-exported/integration/recipes/README.md +0 -136
  86. package/ai-exported/integration/recipes/backend-queries.md +0 -157
  87. package/ai-exported/integration/recipes/bitcoin.md +0 -193
  88. package/ai-exported/integration/recipes/bridge.md +0 -174
  89. package/ai-exported/integration/recipes/dex.md +0 -204
  90. package/ai-exported/integration/recipes/invalidations.md +0 -115
  91. package/ai-exported/integration/recipes/migration.md +0 -212
  92. package/ai-exported/integration/recipes/money-market.md +0 -206
  93. package/ai-exported/integration/recipes/mutation-error-handling.md +0 -118
  94. package/ai-exported/integration/recipes/observability.md +0 -93
  95. package/ai-exported/integration/recipes/setup.md +0 -144
  96. package/ai-exported/integration/recipes/staking.md +0 -202
  97. package/ai-exported/integration/recipes/swap.md +0 -272
  98. package/ai-exported/integration/recipes/wallet-connectivity.md +0 -101
  99. package/ai-exported/integration/reference/README.md +0 -12
  100. package/ai-exported/integration/reference/glossary.md +0 -188
  101. package/ai-exported/integration/reference/hooks-index.md +0 -190
  102. package/ai-exported/integration/reference/public-api.md +0 -110
  103. package/ai-exported/integration/reference/querykey-conventions.md +0 -179
  104. package/ai-exported/migration/README.md +0 -60
  105. package/ai-exported/migration/ai-rules.md +0 -81
  106. package/ai-exported/migration/breaking-changes/hook-signatures.md +0 -233
  107. package/ai-exported/migration/breaking-changes/querykey-conventions.md +0 -108
  108. package/ai-exported/migration/breaking-changes/result-handling.md +0 -211
  109. package/ai-exported/migration/breaking-changes/sdk-leakage.md +0 -165
  110. package/ai-exported/migration/checklist.md +0 -89
  111. package/ai-exported/migration/features/README.md +0 -34
  112. package/ai-exported/migration/features/auxiliary-services.md +0 -114
  113. package/ai-exported/migration/features/bitcoin.md +0 -88
  114. package/ai-exported/migration/features/bridge.md +0 -123
  115. package/ai-exported/migration/features/dex.md +0 -101
  116. package/ai-exported/migration/features/migration.md +0 -120
  117. package/ai-exported/migration/features/money-market.md +0 -97
  118. package/ai-exported/migration/features/staking.md +0 -109
  119. package/ai-exported/migration/features/swap.md +0 -118
  120. package/ai-exported/migration/recipes.md +0 -188
  121. package/ai-exported/migration/reference/README.md +0 -15
  122. package/ai-exported/migration/reference/deleted-hooks.md +0 -110
  123. package/ai-exported/migration/reference/error-shape-crosswalk.md +0 -144
  124. package/ai-exported/migration/reference/renamed-hooks.md +0 -66
  125. package/dist/index.cjs +0 -2642
  126. package/dist/index.cjs.map +0 -1
  127. package/dist/index.d.cts +0 -1550
  128. package/dist/index.mjs.map +0 -1
  129. package/src/hooks/backend/useBackendSubmitSwapTxStatus.ts +0 -59
package/package.json CHANGED
@@ -1,16 +1,32 @@
1
1
  {
2
2
  "name": "@sodax/dapp-kit",
3
+ "private": false,
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
3
7
  "license": "MIT",
4
- "version": "2.0.0-rc.2",
5
- "description": "dapp-kit of New World",
8
+ "version": "2.0.0-rc.20",
9
+ "description": "React hooks for building dApps on the SODAX cross-chain DeFi platform",
10
+ "keywords": [
11
+ "sodax",
12
+ "dapp-kit",
13
+ "react",
14
+ "react-query",
15
+ "hooks",
16
+ "defi"
17
+ ],
18
+ "homepage": "https://github.com/icon-project/sodax-sdks/tree/main/packages/dapp-kit",
19
+ "bugs": {
20
+ "url": "https://github.com/icon-project/sodax-sdks/issues"
21
+ },
6
22
  "type": "module",
7
- "main": "dist/index.cjs",
23
+ "main": "dist/index.mjs",
8
24
  "types": "dist/index.d.ts",
9
25
  "module": "dist/index.mjs",
10
26
  "files": [
11
27
  "dist",
12
- "src",
13
- "ai-exported"
28
+ "!dist/**/*.map",
29
+ "src"
14
30
  ],
15
31
  "repository": {
16
32
  "type": "git",
@@ -18,29 +34,31 @@
18
34
  },
19
35
  "dependencies": {
20
36
  "viem": "2.29.2",
21
- "@sodax/sdk": "2.0.0-rc.2"
37
+ "@sodax/sdk": "2.0.0-rc.20"
22
38
  },
23
39
  "devDependencies": {
40
+ "@arethetypeswrong/cli": "0.17.4",
24
41
  "@tanstack/react-query": "5.87.4",
25
42
  "@types/react": "19.0.8",
26
43
  "knip": "5.30.5",
44
+ "tslib": "2.8.1",
27
45
  "tsup": "8.5.0",
28
46
  "typescript": "5.5.4",
29
- "vitest": "2.1.9"
47
+ "vitest": "3.2.6"
30
48
  },
31
49
  "peerDependencies": {
32
50
  "@tanstack/react-query": "5.x",
33
51
  "react": ">=18"
34
52
  },
35
53
  "engines": {
36
- "node": ">=20.0.0"
54
+ "node": ">=20.12.0"
37
55
  },
56
+ "sideEffects": false,
38
57
  "exports": {
39
58
  "./package.json": "./package.json",
40
59
  ".": {
41
60
  "types": "./dist/index.d.ts",
42
- "import": "./dist/index.mjs",
43
- "require": "./dist/index.cjs"
61
+ "import": "./dist/index.mjs"
44
62
  }
45
63
  },
46
64
  "scripts": {
@@ -50,14 +68,8 @@
50
68
  "clean": "rm -rf dist && rm -rf node_modules && rm -rf .turbo",
51
69
  "pretty": "biome format . --write",
52
70
  "checkTs": "tsc --noEmit",
53
- "knip": "knip",
54
- "lint": "biome lint . --write",
55
- "check:ai-exported": "bash ./scripts/check-ai-exported.sh",
56
- "check:ai-scope": "bash ./scripts/check-ai-scope.sh",
57
- "check:ai-links": "bash ./scripts/check-ai-links.sh",
58
- "check:ai-imports": "bash ./scripts/check-ai-imports.sh",
59
- "check:ai-snippets": "bash ./scripts/check-ai-snippets.sh",
60
- "check:ai-keys": "bash ./scripts/check-ai-keys.sh",
61
- "check:ai-consistency": "bash ./scripts/check-ai-consistency.sh"
71
+ "check-exports": "attw --pack --profile esm-only",
72
+ "check:knip": "knip",
73
+ "lint": "biome lint . --write"
62
74
  }
63
75
  }
@@ -7,13 +7,13 @@ const HOOKS_DIR = resolve(fileURLToPath(import.meta.url), '..');
7
7
 
8
8
  /**
9
9
  * Manifest of every mutation hook. `nativeThrow: true` marks hooks whose underlying SDK methods
10
- * throw natively (Radfi APIs) and so don't need `unwrapResult`.
10
+ * throw natively (Bound Exchange APIs) and so don't need `unwrapResult`.
11
11
  *
12
12
  * To add a new mutation hook, add its path here. The friction is intentional — it forces explicit
13
13
  * registration so the contract is enforced from day one.
14
14
  */
15
15
  const HOOKS: Array<{ path: string; nativeThrow?: true }> = [
16
- { path: 'backend/useBackendSubmitSwapTx.ts' },
16
+ { path: 'bitcoin/useEnsureRadfiAccessToken.ts', nativeThrow: true },
17
17
  { path: 'bitcoin/useFundTradingWallet.ts', nativeThrow: true },
18
18
  { path: 'bitcoin/useRadfiAuth.ts', nativeThrow: true },
19
19
  { path: 'bitcoin/useRadfiWithdraw.ts', nativeThrow: true },
@@ -26,6 +26,10 @@ const HOOKS: Array<{ path: string; nativeThrow?: true }> = [
26
26
  { path: 'dex/useDexDeposit.ts' },
27
27
  { path: 'dex/useDexWithdraw.ts' },
28
28
  { path: 'dex/useSupplyLiquidity.ts' },
29
+ { path: 'leverageYield/useLeverageYieldDeposit.ts' },
30
+ { path: 'leverageYield/useLeverageYieldNotifySolver.ts' },
31
+ { path: 'leverageYield/useLeverageYieldVaultSwap.ts' },
32
+ { path: 'leverageYield/useLeverageYieldWithdraw.ts' },
29
33
  { path: 'migrate/useMigrateBaln.ts' },
30
34
  { path: 'migrate/useMigrateIcxToSoda.ts' },
31
35
  { path: 'migrate/useMigratebnUSD.ts' },
@@ -38,9 +42,12 @@ const HOOKS: Array<{ path: string; nativeThrow?: true }> = [
38
42
  { path: 'mm/useWithdraw.ts' },
39
43
  { path: 'partner/useApproveToken.ts' },
40
44
  { path: 'partner/useFeeClaimSwap.ts' },
45
+ { path: 'partner/useFeeClaimWithdraw.ts' },
46
+ { path: 'partner/usePartnerCancelIntent.ts' },
41
47
  { path: 'partner/useSetSwapPreference.ts' },
42
48
  { path: 'recovery/useWithdrawHubAsset.ts' },
43
49
  { path: 'shared/useEstimateGas.ts' },
50
+ { path: 'shared/useRegisterNearStorage.ts', nativeThrow: true },
44
51
  { path: 'staking/useCancelUnstake.ts' },
45
52
  { path: 'staking/useClaim.ts' },
46
53
  { path: 'staking/useInstantUnstake.ts' },
@@ -54,6 +61,12 @@ const HOOKS: Array<{ path: string; nativeThrow?: true }> = [
54
61
  { path: 'swap/useCreateLimitOrder.ts' },
55
62
  { path: 'swap/useSwap.ts' },
56
63
  { path: 'swap/useSwapApprove.ts' },
64
+ { path: 'swapsApi/useSwapsApiApprove.ts' },
65
+ { path: 'swapsApi/useSwapsApiCancelIntent.ts' },
66
+ { path: 'swapsApi/useSwapsApiCreateIntent.ts' },
67
+ { path: 'swapsApi/useSwapsApiCreateLimitOrder.ts' },
68
+ { path: 'swapsApi/useSwapsApiSubmitIntent.ts' },
69
+ { path: 'swapsApi/useSwapsApiSubmitTx.ts' },
57
70
  ];
58
71
 
59
72
  describe.each(HOOKS)('mutation hook contract: $path', ({ path, nativeThrow }) => {
@@ -12,10 +12,6 @@ export { useBackendIntentByTxHash } from './useBackendIntentByTxHash.js';
12
12
  export { useBackendIntentByHash } from './useBackendIntentByHash.js';
13
13
  export { useBackendUserIntents } from './useBackendUserIntents.js';
14
14
 
15
- // Swap submit-tx hooks
16
- export { useBackendSubmitSwapTx } from './useBackendSubmitSwapTx.js';
17
- export { useBackendSubmitSwapTxStatus } from './useBackendSubmitSwapTxStatus.js';
18
-
19
15
  // Solver hooks
20
16
  export { useBackendOrderbook } from './useBackendOrderbook.js';
21
17
 
@@ -26,4 +22,4 @@ export { useBackendMoneyMarketAsset } from './useBackendMoneyMarketAsset.js';
26
22
  export { useBackendMoneyMarketAssetBorrowers } from './useBackendMoneyMarketAssetBorrowers.js';
27
23
  export { useBackendMoneyMarketAssetSuppliers } from './useBackendMoneyMarketAssetSuppliers.js';
28
24
  export { useBackendAllMoneyMarketBorrowers } from './useBackendAllMoneyMarketBorrowers.js';
29
- export * from './types.js';
25
+ export * from './types.js';
@@ -1,9 +1,11 @@
1
1
  export * from './useRadfiAuth.js';
2
+ export * from './useEnsureRadfiAccessToken.js';
2
3
  export * from './useRadfiSession.js';
3
4
  export * from './useFundTradingWallet.js';
4
5
  export * from './useBitcoinBalance.js';
5
6
  export * from './useTradingWallet.js';
6
7
  export * from './useTradingWalletBalance.js';
8
+ export * from './useBitcoinTradingSetup.js';
7
9
  export * from './useExpiredUtxos.js';
8
10
  export * from './useRenewUtxos.js';
9
11
  export * from './useRadfiWithdraw.js';
@@ -0,0 +1,54 @@
1
+ import { ChainKeys } from '@sodax/sdk';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import type { RadfiSession } from './useRadfiAuth.js';
4
+ import { loadRadfiSession } from './useRadfiAuth.js';
5
+ import { resolveBtcReadAddress } from './resolveBtcReadAddress.js';
6
+
7
+ // resolveBtcReadAddress reads the Bound Exchange session via loadRadfiSession (localStorage-backed).
8
+ // The dapp-kit test env is `node` (no localStorage), so mock the session lookup to drive each branch.
9
+ vi.mock('./useRadfiAuth.js', () => ({
10
+ loadRadfiSession: vi.fn(),
11
+ }));
12
+
13
+ const mockLoadRadfiSession = vi.mocked(loadRadfiSession);
14
+
15
+ const PERSONAL_ADDRESS = 'bc1qpersonal00000000000000000000000000000';
16
+ const TRADING_ADDRESS = 'bc1qtrading000000000000000000000000000000';
17
+
18
+ const session = (tradingAddress: string): RadfiSession => ({
19
+ accessToken: 'access',
20
+ refreshToken: 'refresh',
21
+ tradingAddress,
22
+ publicKey: 'pub',
23
+ });
24
+
25
+ describe('resolveBtcReadAddress', () => {
26
+ beforeEach(() => {
27
+ mockLoadRadfiSession.mockReset();
28
+ });
29
+
30
+ it('passes the address through unchanged for non-Bitcoin chains (no session lookup)', () => {
31
+ const result = resolveBtcReadAddress(ChainKeys.ARBITRUM_MAINNET, PERSONAL_ADDRESS);
32
+
33
+ expect(result).toBe(PERSONAL_ADDRESS);
34
+ expect(mockLoadRadfiSession).not.toHaveBeenCalled();
35
+ });
36
+
37
+ it('returns the trading address from the local session for Bitcoin', () => {
38
+ mockLoadRadfiSession.mockReturnValue(session(TRADING_ADDRESS));
39
+
40
+ const result = resolveBtcReadAddress(ChainKeys.BITCOIN_MAINNET, PERSONAL_ADDRESS);
41
+
42
+ expect(result).toBe(TRADING_ADDRESS);
43
+ // The session is keyed by the personal address.
44
+ expect(mockLoadRadfiSession).toHaveBeenCalledWith(PERSONAL_ADDRESS);
45
+ });
46
+
47
+ it('falls back to the personal address for Bitcoin when there is no session', () => {
48
+ mockLoadRadfiSession.mockReturnValue(null);
49
+
50
+ const result = resolveBtcReadAddress(ChainKeys.BITCOIN_MAINNET, PERSONAL_ADDRESS);
51
+
52
+ expect(result).toBe(PERSONAL_ADDRESS);
53
+ });
54
+ });
@@ -0,0 +1,21 @@
1
+ import { ChainKeys, type SpokeChainKey } from '@sodax/sdk';
2
+ import { loadRadfiSession } from './useRadfiAuth.js';
3
+
4
+ /**
5
+ * Resolve a spoke address for READ queries (positions, balances, hub-wallet display).
6
+ *
7
+ * Bitcoin positions live under the Bound Exchange trading-wallet-derived hub wallet, so for Bitcoin we
8
+ * resolve to the trading address from the locally-persisted Bound Exchange session. This is intentionally
9
+ * a LOCAL lookup (no network call): a transient Bound Exchange API outage can never make a real position
10
+ * read as empty, and reads never throw "Trading wallet not found". When there is no session, the
11
+ * user has no Bitcoin position to show, so the original (personal) address is returned — deriving
12
+ * an empty hub wallet, which is correct. Non-Bitcoin chains pass through unchanged.
13
+ *
14
+ * The WRITE path resolves the trading address authoritatively in the SDK
15
+ * (`getEffectiveWalletAddress`, called from the money-market create*Intent flows); reads
16
+ * deliberately use this lighter, fail-safe path.
17
+ */
18
+ export function resolveBtcReadAddress(chainKey: SpokeChainKey, address: string): string {
19
+ if (chainKey !== ChainKeys.BITCOIN_MAINNET) return address;
20
+ return loadRadfiSession(address)?.tradingAddress ?? address;
21
+ }
@@ -0,0 +1,45 @@
1
+ import {
2
+ ChainKeys,
3
+ type IBitcoinWalletProvider,
4
+ type IWalletProvider,
5
+ type RadfiWalletBalance,
6
+ type SpokeChainKey,
7
+ } from '@sodax/sdk';
8
+ import { useTradingWallet } from './useTradingWallet.js';
9
+ import { useTradingWalletBalance } from './useTradingWalletBalance.js';
10
+
11
+ export interface UseBitcoinTradingSetupParams {
12
+ chainKey: SpokeChainKey;
13
+ /** This side's wallet provider + account, e.g. `useWalletProvider` / `useXAccount`. */
14
+ walletProvider: IWalletProvider | undefined;
15
+ address: string | undefined;
16
+ }
17
+
18
+ export interface BitcoinTradingSetup {
19
+ wallet: IBitcoinWalletProvider | undefined;
20
+ tradingBalance: RadfiWalletBalance | undefined;
21
+ }
22
+
23
+ const INERT: BitcoinTradingSetup = { wallet: undefined, tradingBalance: undefined };
24
+
25
+ /**
26
+ * Bitcoin trading-wallet setup for one side of a cross-chain flow: Bitcoin funds move through a
27
+ * Bound Exchange (Radfi) trading wallet, not the personal wallet. Inert (no work) unless `chainKey`
28
+ * is Bitcoin. Wallet-layer inputs are passed in — this package doesn't depend on wallet-sdk-react.
29
+ */
30
+ export function useBitcoinTradingSetup({
31
+ chainKey,
32
+ walletProvider,
33
+ address,
34
+ }: UseBitcoinTradingSetupParams): BitcoinTradingSetup {
35
+ const isBitcoin = chainKey === ChainKeys.BITCOIN_MAINNET;
36
+ // Safe: when this side is Bitcoin its provider IS the Bitcoin one (TS can't relate chainKey to provider type).
37
+ const wallet = isBitcoin ? (walletProvider as IBitcoinWalletProvider | undefined) : undefined;
38
+
39
+ // Hooks run every render; undefined inputs keep the Bound balance query disabled when not Bitcoin.
40
+ const { tradingAddress } = useTradingWallet(isBitcoin ? address : undefined);
41
+ const { data: tradingBalance } = useTradingWalletBalance({ params: { walletProvider: wallet, tradingAddress } });
42
+
43
+ if (!isBitcoin) return INERT;
44
+ return { wallet, tradingBalance };
45
+ }
@@ -0,0 +1,57 @@
1
+ import type { IBitcoinWalletProvider } from '@sodax/sdk';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import type { MutationHookParams } from '../shared/types.js';
4
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
5
+ import { loadRadfiSession, saveRadfiSession } from './useRadfiAuth.js';
6
+
7
+ export type UseEnsureRadfiAccessTokenVars = {
8
+ walletProvider: IBitcoinWalletProvider;
9
+ };
10
+
11
+ /**
12
+ * Ensure a valid Bound Exchange access token and return it. Refreshes the existing token (no
13
+ * signature prompt) when a refresh token is available, falling back to a full BIP322 re-auth only if
14
+ * refresh fails. Bound tokens are short-lived, so call this right before a Bitcoin-source
15
+ * createIntent — forward the returned token via the typed `extras.bound.accessToken` slot (SDK in-process)
16
+ * or the `accessToken` body field on the backend DTO — or before the client-side sign + co-sign step.
17
+ *
18
+ * @example
19
+ * const { mutateAsync: ensureToken } = useEnsureRadfiAccessToken();
20
+ * const accessToken = await ensureToken({ walletProvider });
21
+ * // SDK in-process (Bitcoin-gated extras):
22
+ * await sodax.swaps.createIntent({ params, extras: { bound: { accessToken } }, raw: true });
23
+ * // or backend createIntent — token in the body, not an x-bound-access-token header:
24
+ * await createIntent({ body: { ...body, accessToken } });
25
+ */
26
+ export function useEnsureRadfiAccessToken({
27
+ mutationOptions,
28
+ }: MutationHookParams<string, UseEnsureRadfiAccessTokenVars> = {}): SafeUseMutationResult<
29
+ string,
30
+ Error,
31
+ UseEnsureRadfiAccessTokenVars
32
+ > {
33
+ const { sodax } = useSodaxContext();
34
+ return useSafeMutation<string, Error, UseEnsureRadfiAccessTokenVars>({
35
+ mutationKey: ['bitcoin', 'ensureAccessToken'],
36
+ ...mutationOptions,
37
+ mutationFn: async ({ walletProvider }) => {
38
+ const radfi = sodax.spoke.bitcoin.radfi;
39
+ const walletAddress = await walletProvider.getWalletAddress();
40
+ // Seed in-memory tokens from the saved session so a refresh can run without a re-sign popup.
41
+ const session = loadRadfiSession(walletAddress);
42
+ if (session?.refreshToken && !radfi.refreshToken) {
43
+ radfi.setRadfiAccessToken(session.accessToken, session.refreshToken);
44
+ }
45
+ await radfi.ensureRadfiAccessToken(walletProvider);
46
+ const accessToken = radfi.accessToken;
47
+ if (!accessToken) {
48
+ throw new Error('Failed to obtain a Bound Exchange access token');
49
+ }
50
+ // Persist refreshed tokens so a later reload can refresh again without re-signing.
51
+ if (session) {
52
+ saveRadfiSession(walletAddress, { ...session, accessToken, refreshToken: radfi.refreshToken });
53
+ }
54
+ return accessToken;
55
+ },
56
+ });
57
+ }
@@ -11,7 +11,7 @@ export type UseFundTradingWalletVars = {
11
11
  };
12
12
 
13
13
  /**
14
- * React hook for funding the user's Radfi trading wallet from their personal Bitcoin wallet.
14
+ * React hook for funding the user's Bound Exchange trading wallet from their personal Bitcoin wallet.
15
15
  * Pure mutation: pass `{ amount, walletProvider }` to `mutate({...})`. Returns the broadcast tx
16
16
  * id on success.
17
17
  */
@@ -45,7 +45,7 @@ export function clearRadfiSession(address: string): void {
45
45
  }
46
46
 
47
47
  /**
48
- * React hook for authenticating with Radfi via BIP322-signed message. Pure mutation: pass
48
+ * React hook for authenticating with Bound Exchange via BIP322-signed message. Pure mutation: pass
49
49
  * `{ walletProvider }` to `mutate({...})`. The hook itself takes no arguments other than the
50
50
  * structural `mutationOptions` slot.
51
51
  */
@@ -95,7 +95,7 @@ export function useRadfiAuth({
95
95
  }
96
96
 
97
97
  throw new Error(
98
- 'This wallet is already registered with Radfi from another session. ' +
98
+ 'This wallet is already registered with Bound Exchange from another session. ' +
99
99
  'Please clear your browser storage for this site and try again, ' +
100
100
  'or wait for the previous session to expire.',
101
101
  );
@@ -19,7 +19,7 @@ type WithdrawResult = {
19
19
  };
20
20
 
21
21
  /**
22
- * React hook for withdrawing BTC from the user's Radfi trading wallet back to their personal
22
+ * React hook for withdrawing BTC from the user's Bound Exchange trading wallet back to their personal
23
23
  * Bitcoin wallet. Pure mutation: pass all inputs (including the wallet provider) to
24
24
  * `mutate({...})`.
25
25
  */
@@ -44,7 +44,7 @@ export function useRadfiWithdraw({
44
44
  const accessToken = session?.accessToken || radfi.accessToken;
45
45
 
46
46
  if (!accessToken) {
47
- throw new Error('Radfi authentication required. Please login first.');
47
+ throw new Error('Bound Exchange authentication required. Please login first.');
48
48
  }
49
49
 
50
50
  const buildResult = await radfi.withdrawToUser({ userAddress, amount, tokenId, withdrawTo }, accessToken);
@@ -12,7 +12,7 @@ export type UseRenewUtxosVars = {
12
12
  };
13
13
 
14
14
  /**
15
- * React hook for renewing expired UTXOs in the user's Radfi trading wallet. Pure mutation: pass
15
+ * React hook for renewing expired UTXOs in the user's Bound Exchange trading wallet. Pure mutation: pass
16
16
  * `{ txIdVouts, walletProvider }` to `mutate({...})`.
17
17
  */
18
18
  export function useRenewUtxos({
@@ -32,7 +32,7 @@ export function useRenewUtxos({
32
32
  const accessToken = session?.accessToken || radfi.accessToken;
33
33
 
34
34
  if (!accessToken) {
35
- throw new Error('Radfi authentication required. Please login first.');
35
+ throw new Error('Bound Exchange authentication required. Please login first.');
36
36
  }
37
37
 
38
38
  const buildResult = await radfi.buildRenewUtxoTransaction({ userAddress, txIdVouts }, accessToken);
@@ -5,7 +5,7 @@ type UseTradingWalletReturn = {
5
5
  };
6
6
 
7
7
  /**
8
- * Returns the Radfi trading wallet address from the persisted session.
8
+ * Returns the Bound Exchange trading wallet address from the persisted session.
9
9
  * Trading wallet is created automatically during authentication — no API call needed.
10
10
  */
11
11
  export function useTradingWallet(walletAddress: string | undefined): UseTradingWalletReturn {
@@ -4,9 +4,11 @@ export * from './bitcoin/index.js';
4
4
  export * from './mm/index.js';
5
5
  export * from './swap/index.js';
6
6
  export * from './backend/index.js';
7
+ export * from './swapsApi/index.js';
7
8
  export * from './bridge/index.js';
8
9
  export * from './staking/index.js';
9
10
  export * from './partner/index.js';
10
11
  export * from './recovery/index.js';
11
12
  export * from './migrate/index.js';
12
13
  export * from './dex/index.js';
14
+ export * from './leverageYield/index.js';
@@ -0,0 +1,9 @@
1
+ export * from './useLeverageYieldEffectiveApr.js';
2
+ export * from './useLeverageYieldPosition.js';
3
+ export * from './useLeverageYieldTotalAssets.js';
4
+ export * from './useLeverageYieldPreviewRedeem.js';
5
+ export * from './useLeverageYieldShareBalances.js';
6
+ export * from './useLeverageYieldDeposit.js';
7
+ export * from './useLeverageYieldNotifySolver.js';
8
+ export * from './useLeverageYieldVaultSwap.js';
9
+ export * from './useLeverageYieldWithdraw.js';
@@ -0,0 +1,40 @@
1
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
2
+ import type { LeverageYieldSwapPayload, LeverageYieldSwapDepositParams } from '@sodax/sdk';
3
+ import type { MutationHookParams } from '../shared/types.js';
4
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
5
+ import { unwrapResult } from '../shared/unwrapResult.js';
6
+
7
+ /** Mutation variables for {@link useLeverageYieldDeposit} — the swap-style deposit inputs. */
8
+ export type UseLeverageYieldDepositVars = LeverageYieldSwapDepositParams;
9
+
10
+ /**
11
+ * Builds the `LeverageYieldSwapPayload` for a leverage-yield deposit (any token → `lsoda*` shares,
12
+ * delivered to the user's hub wallet). Spread the returned payload into
13
+ * {@link useLeverageYieldVaultSwap}.
14
+ *
15
+ * This is a builder, not an executor — it derives the hub wallet and assembles the intent; the
16
+ * actual swap is relayed by `useLeverageYieldVaultSwap`. Throws on SDK failure so React Query's
17
+ * error model engages; returns the unwrapped `LeverageYieldSwapPayload` on success.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const { mutateAsyncSafe: buildDeposit } = useLeverageYieldDeposit();
22
+ * const built = await buildDeposit({ vault, srcChainKey, srcAddress, inputToken, inputAmount, minOutputAmount });
23
+ * if (built.ok) vaultSwap({ ...built.value, walletProvider });
24
+ * ```
25
+ */
26
+ export function useLeverageYieldDeposit({
27
+ mutationOptions,
28
+ }: MutationHookParams<LeverageYieldSwapPayload, UseLeverageYieldDepositVars> = {}): SafeUseMutationResult<
29
+ LeverageYieldSwapPayload,
30
+ Error,
31
+ UseLeverageYieldDepositVars
32
+ > {
33
+ const { sodax } = useSodaxContext();
34
+
35
+ return useSafeMutation<LeverageYieldSwapPayload, Error, UseLeverageYieldDepositVars>({
36
+ mutationKey: ['leverageYield', 'deposit'],
37
+ ...mutationOptions,
38
+ mutationFn: async vars => unwrapResult(await sodax.leverageYield.deposit(vars)),
39
+ });
40
+ }
@@ -0,0 +1,42 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import type { Address, LeverageYieldEffectiveApr } from '@sodax/sdk';
4
+ import type { ReadHookParams } from '../shared/types.js';
5
+
6
+ export type UseLeverageYieldEffectiveAprParams = ReadHookParams<
7
+ LeverageYieldEffectiveApr,
8
+ { vault: Address | undefined }
9
+ >;
10
+
11
+ /**
12
+ * Reads a leverage-yield vault's effective APR — AAVE supply/borrow rates plus the LSD
13
+ * staking yield, with the vault's leverage formula re-applied on the boosted supply side.
14
+ *
15
+ * The underlying SDK call does the on-chain reads (AAVE rates + `targetLTV`) and the
16
+ * off-chain LSD fetch in parallel. Rates drift slowly, so the default refresh is 60s.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const { data: apr } = useLeverageYieldEffectiveApr({ params: { vault: vault.vault } });
21
+ * ```
22
+ */
23
+ export function useLeverageYieldEffectiveApr({
24
+ params,
25
+ queryOptions,
26
+ }: UseLeverageYieldEffectiveAprParams = {}): UseQueryResult<LeverageYieldEffectiveApr, Error> {
27
+ const { sodax } = useSodaxContext();
28
+ const vault = params?.vault;
29
+
30
+ return useQuery<LeverageYieldEffectiveApr, Error>({
31
+ queryKey: ['leverageYield', 'effectiveApr', vault],
32
+ queryFn: async () => {
33
+ if (!vault) throw new Error('vault is required');
34
+ const result = await sodax.leverageYield.getEffectiveApr(vault);
35
+ if (!result.ok) throw result.error;
36
+ return result.value;
37
+ },
38
+ enabled: !!vault,
39
+ refetchInterval: 60_000,
40
+ ...queryOptions,
41
+ });
42
+ }
@@ -0,0 +1,34 @@
1
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
2
+ import type { SolverExecutionRequest, SolverExecutionResponse } from '@sodax/sdk';
3
+ import type { MutationHookParams } from '../shared/types.js';
4
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
5
+ import { unwrapResult } from '../shared/unwrapResult.js';
6
+
7
+ /** Mutation variables for {@link useLeverageYieldNotifySolver} — the hub-side intent tx hash. */
8
+ export type UseLeverageYieldNotifySolverVars = SolverExecutionRequest;
9
+
10
+ /**
11
+ * Notifies the solver that a leverage-yield vault intent landed on the hub, triggering the fill.
12
+ * The standalone notify step for the manual create → relay → notify flow: build the intent with
13
+ * `sodax.leverageYield.createVaultIntent`, relay it yourself, then call this with the hub-side
14
+ * intent tx hash. The end-to-end {@link useLeverageYieldVaultSwap} already calls notifySolver
15
+ * internally — only reach for this hook when driving the relay manually.
16
+ *
17
+ * Throws on SDK failure so React Query's error model engages; returns the unwrapped
18
+ * `SolverExecutionResponse` (`{ answer: 'OK', intent_hash }`) on success.
19
+ */
20
+ export function useLeverageYieldNotifySolver({
21
+ mutationOptions,
22
+ }: MutationHookParams<SolverExecutionResponse, UseLeverageYieldNotifySolverVars> = {}): SafeUseMutationResult<
23
+ SolverExecutionResponse,
24
+ Error,
25
+ UseLeverageYieldNotifySolverVars
26
+ > {
27
+ const { sodax } = useSodaxContext();
28
+
29
+ return useSafeMutation<SolverExecutionResponse, Error, UseLeverageYieldNotifySolverVars>({
30
+ mutationKey: ['leverageYield', 'notifySolver'],
31
+ ...mutationOptions,
32
+ mutationFn: async vars => unwrapResult(await sodax.leverageYield.notifySolver(vars)),
33
+ });
34
+ }
@@ -0,0 +1,40 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import type { Address, LeverageYieldPosition } from '@sodax/sdk';
4
+ import type { ReadHookParams } from '../shared/types.js';
5
+
6
+ export type UseLeverageYieldPositionParams = ReadHookParams<LeverageYieldPosition, { vault: Address | undefined }>;
7
+
8
+ /**
9
+ * Reads a leverage-yield vault's live position snapshot via the vault's `getPositionDetails`:
10
+ * collateral, debt, current LTV (drift vs `targetLTV`), health factor (∞ when no debt), and
11
+ * idle (not-yet-deployed) asset.
12
+ *
13
+ * LTV shifts with each rebalance/rate tick, so the default refresh (30s) is faster than the
14
+ * APR/stats reads.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const { data: position } = useLeverageYieldPosition({ params: { vault: vault.vault } });
19
+ * ```
20
+ */
21
+ export function useLeverageYieldPosition({
22
+ params,
23
+ queryOptions,
24
+ }: UseLeverageYieldPositionParams = {}): UseQueryResult<LeverageYieldPosition, Error> {
25
+ const { sodax } = useSodaxContext();
26
+ const vault = params?.vault;
27
+
28
+ return useQuery<LeverageYieldPosition, Error>({
29
+ queryKey: ['leverageYield', 'position', vault],
30
+ queryFn: async () => {
31
+ if (!vault) throw new Error('vault is required');
32
+ const result = await sodax.leverageYield.getPosition(vault);
33
+ if (!result.ok) throw result.error;
34
+ return result.value;
35
+ },
36
+ enabled: !!vault,
37
+ refetchInterval: 30_000,
38
+ ...queryOptions,
39
+ });
40
+ }