@earnforge/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,313 @@
1
+ import { ReactNode } from "react";
2
+ import { AllowanceResult, ApprovalTx, ApyDataPoint, DepositQuoteResult, EarnForge, PortfolioResponse, PreflightReport, RedeemQuoteResult, RiskScore, StrategyConfig, StrategyPreset, SuggestResult, Vault } from "@earnforge/sdk";
3
+
4
+ //#region src/context.d.ts
5
+ declare const EarnForgeContext: any;
6
+ interface EarnForgeProviderProps {
7
+ sdk: EarnForge;
8
+ children: ReactNode;
9
+ }
10
+ /**
11
+ * Wrap your application with `EarnForgeProvider` to make the SDK
12
+ * instance available to all hooks via React context.
13
+ *
14
+ * ```tsx
15
+ * const forge = createEarnForge({ composerApiKey: '...' });
16
+ * <EarnForgeProvider sdk={forge}>
17
+ * <App />
18
+ * </EarnForgeProvider>
19
+ * ```
20
+ */
21
+ declare function EarnForgeProvider({
22
+ sdk,
23
+ children
24
+ }: EarnForgeProviderProps): any;
25
+ /**
26
+ * Internal helper — returns the SDK instance from context
27
+ * or throws if used outside an `EarnForgeProvider`.
28
+ */
29
+ declare function useEarnForge(): EarnForge;
30
+ //#endregion
31
+ //#region src/hooks/useVaults.d.ts
32
+ interface UseVaultsParams {
33
+ chainId?: number;
34
+ asset?: string;
35
+ minTvl?: number;
36
+ sortBy?: string;
37
+ limit?: number;
38
+ strategy?: StrategyPreset;
39
+ }
40
+ interface UseVaultsReturn {
41
+ data: Vault[] | undefined;
42
+ isLoading: boolean;
43
+ error: Error | null;
44
+ fetchMore: () => void;
45
+ hasMore: boolean;
46
+ }
47
+ /**
48
+ * Fetch a paginated list of vaults with optional filters.
49
+ * Resets accumulated data when params change.
50
+ *
51
+ * ```tsx
52
+ * const { data, isLoading, fetchMore, hasMore } = useVaults({ chainId: 8453 });
53
+ * ```
54
+ */
55
+ declare function useVaults(params?: UseVaultsParams): UseVaultsReturn;
56
+ //#endregion
57
+ //#region src/hooks/useVault.d.ts
58
+ interface UseVaultReturn {
59
+ data: Vault | undefined;
60
+ isLoading: boolean;
61
+ error: Error | null;
62
+ }
63
+ /**
64
+ * Fetch a single vault by its slug.
65
+ *
66
+ * ```tsx
67
+ * const { data: vault, isLoading } = useVault('aave-v3-usdc-base');
68
+ * ```
69
+ */
70
+ declare function useVault(slug: string | undefined): UseVaultReturn;
71
+ //#endregion
72
+ //#region src/hooks/useEarnTopYield.d.ts
73
+ interface UseEarnTopYieldParams {
74
+ asset?: string;
75
+ chainId?: number;
76
+ limit?: number;
77
+ strategy?: StrategyPreset;
78
+ minTvl?: number;
79
+ }
80
+ interface UseEarnTopYieldReturn {
81
+ data: Vault[] | undefined;
82
+ isLoading: boolean;
83
+ error: Error | null;
84
+ }
85
+ /**
86
+ * Fetch top-yielding vaults sorted by APY.
87
+ *
88
+ * ```tsx
89
+ * const { data } = useEarnTopYield({ asset: 'USDC', limit: 5 });
90
+ * ```
91
+ */
92
+ declare function useEarnTopYield(params?: UseEarnTopYieldParams): UseEarnTopYieldReturn;
93
+ //#endregion
94
+ //#region src/hooks/usePortfolio.d.ts
95
+ interface UsePortfolioReturn {
96
+ data: PortfolioResponse | undefined;
97
+ isLoading: boolean;
98
+ error: Error | null;
99
+ }
100
+ /**
101
+ * Fetch portfolio positions for a wallet address.
102
+ *
103
+ * ```tsx
104
+ * const { data } = usePortfolio('0xabc...');
105
+ * ```
106
+ */
107
+ declare function usePortfolio(wallet: string | undefined): UsePortfolioReturn;
108
+ //#endregion
109
+ //#region src/hooks/useRiskScore.d.ts
110
+ interface UseRiskScoreReturn {
111
+ data: RiskScore | undefined;
112
+ }
113
+ /**
114
+ * Compute a risk score for a vault. This is a synchronous computation
115
+ * wrapped in `useMemo` for referential stability.
116
+ *
117
+ * ```tsx
118
+ * const { data: risk } = useRiskScore(vault);
119
+ * // risk.score, risk.label, risk.breakdown
120
+ * ```
121
+ */
122
+ declare function useRiskScore(vault: Vault | undefined): UseRiskScoreReturn;
123
+ //#endregion
124
+ //#region src/hooks/useStrategy.d.ts
125
+ interface UseStrategyReturn {
126
+ data: StrategyConfig | undefined;
127
+ filters: StrategyConfig['filters'] | undefined;
128
+ sort: StrategyConfig['sort'] | undefined;
129
+ sortDirection: StrategyConfig['sortDirection'] | undefined;
130
+ }
131
+ /**
132
+ * Resolve a strategy preset into its filter configuration.
133
+ * Use the returned `filters` to pass into `useVaults` or `useEarnTopYield`.
134
+ *
135
+ * ```tsx
136
+ * const { filters } = useStrategy('conservative');
137
+ * const { data } = useVaults({ ...filters });
138
+ * ```
139
+ */
140
+ declare function useStrategy(preset: StrategyPreset | undefined): UseStrategyReturn;
141
+ //#endregion
142
+ //#region src/hooks/useSuggest.d.ts
143
+ interface UseSuggestParams {
144
+ amount: number;
145
+ asset?: string;
146
+ maxChains?: number;
147
+ strategy?: StrategyPreset;
148
+ }
149
+ interface UseSuggestReturn {
150
+ data: SuggestResult | undefined;
151
+ isLoading: boolean;
152
+ error: Error | null;
153
+ }
154
+ /**
155
+ * Get a suggested portfolio allocation based on the given parameters.
156
+ *
157
+ * ```tsx
158
+ * const { data } = useSuggest({ amount: 10_000, asset: 'USDC' });
159
+ * // data.allocations — the recommended split
160
+ * ```
161
+ */
162
+ declare function useSuggest(params: UseSuggestParams | undefined): UseSuggestReturn;
163
+ //#endregion
164
+ //#region src/hooks/useApyHistory.d.ts
165
+ interface UseApyHistoryReturn {
166
+ data: ApyDataPoint[] | undefined;
167
+ isLoading: boolean;
168
+ error: Error | null;
169
+ }
170
+ /**
171
+ * Fetch 30-day APY history for a vault from DeFiLlama.
172
+ *
173
+ * Accepts a full Vault object for accurate matching (uses protocol name,
174
+ * chain, underlying tokens, symbol, and TVL proximity). Falls back to
175
+ * the less accurate address+chainId matching when only primitives are given.
176
+ *
177
+ * ```tsx
178
+ * // Preferred: pass the full vault object for accurate DeFiLlama matching
179
+ * const { data: history } = useApyHistory(vault);
180
+ *
181
+ * // Legacy: address + chainId (less accurate matching)
182
+ * const { data: history } = useApyHistory('0xabc...', 8453);
183
+ * ```
184
+ */
185
+ declare function useApyHistory(vault: Vault | undefined): UseApyHistoryReturn;
186
+ declare function useApyHistory(vaultAddress: string | undefined, chainId: number | undefined): UseApyHistoryReturn;
187
+ //#endregion
188
+ //#region src/hooks/useEarnDeposit.d.ts
189
+ /**
190
+ * Deposit state machine:
191
+ *
192
+ * idle --> preflight --> checking-allowance --> approving --> quoting --> ready --> sending --> success
193
+ * \ | | | | | |
194
+ * \________|_______________|___________________|____________|__________|__________|--> error
195
+ *
196
+ * The "checking-allowance" phase verifies the ERC-20 allowance for the fromToken.
197
+ * If allowance is insufficient, "approving" sends an approval tx before quoting.
198
+ */
199
+ type DepositPhase = 'idle' | 'preflight' | 'checking-allowance' | 'approving' | 'quoting' | 'ready' | 'sending' | 'success' | 'error';
200
+ interface DepositState {
201
+ phase: DepositPhase;
202
+ preflightReport: PreflightReport | null;
203
+ allowance: AllowanceResult | null;
204
+ approvalTx: ApprovalTx | null;
205
+ quote: DepositQuoteResult | null;
206
+ txHash: string | null;
207
+ error: Error | null;
208
+ }
209
+ interface UseEarnDepositParams {
210
+ vault: Vault | undefined;
211
+ amount: string;
212
+ wallet: string;
213
+ fromToken?: string;
214
+ fromChain?: number;
215
+ slippage?: number;
216
+ /** JSON-RPC URL for the source chain — needed for allowance checking */
217
+ rpcUrl?: string;
218
+ /** wagmi's sendTransactionAsync function — pass from useSendTransaction() */
219
+ sendTransactionAsync?: (params: {
220
+ to: `0x${string}`;
221
+ data: `0x${string}`;
222
+ value: bigint;
223
+ chainId: number;
224
+ }) => Promise<`0x${string}`>;
225
+ }
226
+ interface UseEarnDepositReturn {
227
+ state: DepositState;
228
+ /** Kick off the preflight -> quote -> ready flow */
229
+ prepare: () => Promise<void>;
230
+ /** Execute the deposit transaction (requires sendTransactionAsync or sendTransaction) */
231
+ execute: () => Promise<void>;
232
+ /** Reset back to idle */
233
+ reset: () => void;
234
+ }
235
+ /**
236
+ * Deposit state machine hook.
237
+ *
238
+ * Flow: idle -> preflight -> quoting -> ready
239
+ * Then call `execute()` to send: ready -> sending -> success
240
+ *
241
+ * ```tsx
242
+ * const { state, prepare, execute, reset } = useEarnDeposit({
243
+ * vault,
244
+ * amount: '100',
245
+ * wallet: address,
246
+ * sendTransactionAsync,
247
+ * });
248
+ * ```
249
+ */
250
+ declare function useEarnDeposit(params: UseEarnDepositParams): UseEarnDepositReturn;
251
+ //#endregion
252
+ //#region src/hooks/useEarnRedeem.d.ts
253
+ /**
254
+ * Redeem state machine:
255
+ *
256
+ * idle --> preflight --> quoting --> ready --> sending --> success
257
+ * \ | | | |
258
+ * \__________|______________|____________|____________|--> error
259
+ */
260
+ type RedeemPhase = 'idle' | 'preflight' | 'quoting' | 'ready' | 'sending' | 'success' | 'error';
261
+ interface RedeemState {
262
+ phase: RedeemPhase;
263
+ preflightReport: PreflightReport | null;
264
+ quote: RedeemQuoteResult | null;
265
+ txHash: string | null;
266
+ error: Error | null;
267
+ }
268
+ interface UseEarnRedeemParams {
269
+ vault: Vault | undefined;
270
+ /** Amount of vault share tokens to redeem (human-readable) */
271
+ amount: string;
272
+ wallet: string;
273
+ /** Token to receive. Defaults to underlying token on vault chain. */
274
+ toToken?: string;
275
+ /** Destination chain. Defaults to vault chain. */
276
+ toChain?: number;
277
+ slippage?: number;
278
+ /** wagmi's sendTransactionAsync function — pass from useSendTransaction() */
279
+ sendTransactionAsync?: (params: {
280
+ to: `0x${string}`;
281
+ data: `0x${string}`;
282
+ value: bigint;
283
+ chainId: number;
284
+ }) => Promise<`0x${string}`>;
285
+ }
286
+ interface UseEarnRedeemReturn {
287
+ state: RedeemState;
288
+ /** Kick off the preflight -> quote -> ready flow */
289
+ prepare: () => Promise<void>;
290
+ /** Execute the redeem transaction (requires sendTransactionAsync) */
291
+ execute: () => Promise<void>;
292
+ /** Reset back to idle */
293
+ reset: () => void;
294
+ }
295
+ /**
296
+ * Withdrawal/redeem state machine hook.
297
+ *
298
+ * Flow: idle -> preflight -> quoting -> ready
299
+ * Then call `execute()` to send: ready -> sending -> success
300
+ *
301
+ * ```tsx
302
+ * const { state, prepare, execute, reset } = useEarnRedeem({
303
+ * vault,
304
+ * amount: '100',
305
+ * wallet: address,
306
+ * sendTransactionAsync,
307
+ * });
308
+ * ```
309
+ */
310
+ declare function useEarnRedeem(params: UseEarnRedeemParams): UseEarnRedeemReturn;
311
+ //#endregion
312
+ export { type DepositPhase, type DepositState, EarnForgeContext, EarnForgeProvider, type EarnForgeProviderProps, type RedeemPhase, type RedeemState, type UseApyHistoryReturn, type UseEarnDepositParams, type UseEarnDepositReturn, type UseEarnRedeemParams, type UseEarnRedeemReturn, type UseEarnTopYieldParams, type UseEarnTopYieldReturn, type UsePortfolioReturn, type UseRiskScoreReturn, type UseStrategyReturn, type UseSuggestParams, type UseSuggestReturn, type UseVaultReturn, type UseVaultsParams, type UseVaultsReturn, useApyHistory, useEarnDeposit, useEarnForge, useEarnRedeem, useEarnTopYield, usePortfolio, useRiskScore, useStrategy, useSuggest, useVault, useVaults };
313
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/context.ts","../../src/hooks/useVaults.ts","../../src/hooks/useVault.ts","../../src/hooks/useEarnTopYield.ts","../../src/hooks/usePortfolio.ts","../../src/hooks/useRiskScore.ts","../../src/hooks/useStrategy.ts","../../src/hooks/useSuggest.ts","../../src/hooks/useApyHistory.ts","../../src/hooks/useEarnDeposit.ts","../../src/hooks/useEarnRedeem.ts"],"mappings":"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"}
@@ -0,0 +1,629 @@
1
+ import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
2
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
3
+ import { MAX_UINT256, buildApprovalTx, checkAllowance, getStrategy, toSmallestUnit } from "@earnforge/sdk";
4
+ //#region src/context.ts
5
+ const EarnForgeContext = createContext(null);
6
+ /**
7
+ * Wrap your application with `EarnForgeProvider` to make the SDK
8
+ * instance available to all hooks via React context.
9
+ *
10
+ * ```tsx
11
+ * const forge = createEarnForge({ composerApiKey: '...' });
12
+ * <EarnForgeProvider sdk={forge}>
13
+ * <App />
14
+ * </EarnForgeProvider>
15
+ * ```
16
+ */
17
+ function EarnForgeProvider({ sdk, children }) {
18
+ return createElement(EarnForgeContext.Provider, { value: sdk }, children);
19
+ }
20
+ /**
21
+ * Internal helper — returns the SDK instance from context
22
+ * or throws if used outside an `EarnForgeProvider`.
23
+ */
24
+ function useEarnForge() {
25
+ const ctx = useContext(EarnForgeContext);
26
+ if (!ctx) throw new Error("useEarnForge must be used within an <EarnForgeProvider>. Wrap your component tree with <EarnForgeProvider sdk={forge}>.");
27
+ return ctx;
28
+ }
29
+ //#endregion
30
+ //#region src/hooks/useVaults.ts
31
+ /**
32
+ * Fetch a paginated list of vaults with optional filters.
33
+ * Resets accumulated data when params change.
34
+ *
35
+ * ```tsx
36
+ * const { data, isLoading, fetchMore, hasMore } = useVaults({ chainId: 8453 });
37
+ * ```
38
+ */
39
+ function useVaults(params = {}) {
40
+ const sdk = useEarnForge();
41
+ const queryClient = useQueryClient();
42
+ const cursorRef = useRef(null);
43
+ const accumulatedRef = useRef([]);
44
+ const paramsKey = useMemo(() => JSON.stringify({
45
+ chainId: params.chainId,
46
+ asset: params.asset,
47
+ minTvl: params.minTvl,
48
+ sortBy: params.sortBy,
49
+ strategy: params.strategy
50
+ }), [
51
+ params.chainId,
52
+ params.asset,
53
+ params.minTvl,
54
+ params.sortBy,
55
+ params.strategy
56
+ ]);
57
+ useEffect(() => {
58
+ cursorRef.current = null;
59
+ accumulatedRef.current = [];
60
+ }, [paramsKey]);
61
+ const queryKey = useMemo(() => [
62
+ "earnforge",
63
+ "vaults",
64
+ paramsKey,
65
+ cursorRef.current
66
+ ], [paramsKey]);
67
+ const query = useQuery({
68
+ queryKey,
69
+ queryFn: async () => {
70
+ const result = await sdk.vaults.list({
71
+ chainId: params.chainId,
72
+ asset: params.asset,
73
+ minTvl: params.minTvl,
74
+ sortBy: params.sortBy,
75
+ strategy: params.strategy,
76
+ cursor: cursorRef.current ?? void 0
77
+ });
78
+ cursorRef.current = result.nextCursor;
79
+ if (accumulatedRef.current.length === 0) accumulatedRef.current = result.data;
80
+ else accumulatedRef.current = [...accumulatedRef.current, ...result.data];
81
+ return {
82
+ ...result,
83
+ data: params.limit ? accumulatedRef.current.slice(0, params.limit) : accumulatedRef.current
84
+ };
85
+ }
86
+ });
87
+ const fetchMore = useCallback(() => {
88
+ if (cursorRef.current) queryClient.invalidateQueries({ queryKey });
89
+ }, [queryClient, queryKey]);
90
+ return {
91
+ data: query.data?.data,
92
+ isLoading: query.isLoading,
93
+ error: query.error,
94
+ fetchMore,
95
+ hasMore: cursorRef.current !== null
96
+ };
97
+ }
98
+ //#endregion
99
+ //#region src/hooks/useVault.ts
100
+ /**
101
+ * Fetch a single vault by its slug.
102
+ *
103
+ * ```tsx
104
+ * const { data: vault, isLoading } = useVault('aave-v3-usdc-base');
105
+ * ```
106
+ */
107
+ function useVault(slug) {
108
+ const sdk = useEarnForge();
109
+ const query = useQuery({
110
+ queryKey: [
111
+ "earnforge",
112
+ "vault",
113
+ slug
114
+ ],
115
+ queryFn: () => sdk.vaults.get(slug),
116
+ enabled: !!slug
117
+ });
118
+ return {
119
+ data: query.data,
120
+ isLoading: query.isLoading,
121
+ error: query.error
122
+ };
123
+ }
124
+ //#endregion
125
+ //#region src/hooks/useEarnTopYield.ts
126
+ /**
127
+ * Fetch top-yielding vaults sorted by APY.
128
+ *
129
+ * ```tsx
130
+ * const { data } = useEarnTopYield({ asset: 'USDC', limit: 5 });
131
+ * ```
132
+ */
133
+ function useEarnTopYield(params = {}) {
134
+ const sdk = useEarnForge();
135
+ const query = useQuery({
136
+ queryKey: [
137
+ "earnforge",
138
+ "topYield",
139
+ params
140
+ ],
141
+ queryFn: () => sdk.vaults.top({
142
+ asset: params.asset,
143
+ chainId: params.chainId,
144
+ limit: params.limit,
145
+ strategy: params.strategy,
146
+ minTvl: params.minTvl
147
+ })
148
+ });
149
+ return {
150
+ data: query.data,
151
+ isLoading: query.isLoading,
152
+ error: query.error
153
+ };
154
+ }
155
+ //#endregion
156
+ //#region src/hooks/usePortfolio.ts
157
+ /**
158
+ * Fetch portfolio positions for a wallet address.
159
+ *
160
+ * ```tsx
161
+ * const { data } = usePortfolio('0xabc...');
162
+ * ```
163
+ */
164
+ function usePortfolio(wallet) {
165
+ const sdk = useEarnForge();
166
+ const query = useQuery({
167
+ queryKey: [
168
+ "earnforge",
169
+ "portfolio",
170
+ wallet
171
+ ],
172
+ queryFn: () => sdk.portfolio.get(wallet),
173
+ enabled: !!wallet
174
+ });
175
+ return {
176
+ data: query.data,
177
+ isLoading: query.isLoading,
178
+ error: query.error
179
+ };
180
+ }
181
+ //#endregion
182
+ //#region src/hooks/useRiskScore.ts
183
+ /**
184
+ * Compute a risk score for a vault. This is a synchronous computation
185
+ * wrapped in `useMemo` for referential stability.
186
+ *
187
+ * ```tsx
188
+ * const { data: risk } = useRiskScore(vault);
189
+ * // risk.score, risk.label, risk.breakdown
190
+ * ```
191
+ */
192
+ function useRiskScore(vault) {
193
+ const sdk = useEarnForge();
194
+ return { data: useMemo(() => {
195
+ if (!vault) return void 0;
196
+ return sdk.riskScore(vault);
197
+ }, [sdk, vault]) };
198
+ }
199
+ //#endregion
200
+ //#region src/hooks/useStrategy.ts
201
+ /**
202
+ * Resolve a strategy preset into its filter configuration.
203
+ * Use the returned `filters` to pass into `useVaults` or `useEarnTopYield`.
204
+ *
205
+ * ```tsx
206
+ * const { filters } = useStrategy('conservative');
207
+ * const { data } = useVaults({ ...filters });
208
+ * ```
209
+ */
210
+ function useStrategy(preset) {
211
+ const data = useMemo(() => {
212
+ if (!preset) return void 0;
213
+ return getStrategy(preset);
214
+ }, [preset]);
215
+ return {
216
+ data,
217
+ filters: data?.filters,
218
+ sort: data?.sort,
219
+ sortDirection: data?.sortDirection
220
+ };
221
+ }
222
+ //#endregion
223
+ //#region src/hooks/useSuggest.ts
224
+ /**
225
+ * Get a suggested portfolio allocation based on the given parameters.
226
+ *
227
+ * ```tsx
228
+ * const { data } = useSuggest({ amount: 10_000, asset: 'USDC' });
229
+ * // data.allocations — the recommended split
230
+ * ```
231
+ */
232
+ function useSuggest(params) {
233
+ const sdk = useEarnForge();
234
+ const query = useQuery({
235
+ queryKey: [
236
+ "earnforge",
237
+ "suggest",
238
+ params
239
+ ],
240
+ queryFn: () => sdk.suggest({
241
+ amount: params.amount,
242
+ asset: params.asset,
243
+ maxChains: params.maxChains,
244
+ strategy: params.strategy
245
+ }),
246
+ enabled: !!params && params.amount > 0
247
+ });
248
+ return {
249
+ data: query.data,
250
+ isLoading: query.isLoading,
251
+ error: query.error
252
+ };
253
+ }
254
+ //#endregion
255
+ //#region src/hooks/useApyHistory.ts
256
+ function useApyHistory(vaultOrAddress, chainId) {
257
+ const sdk = useEarnForge();
258
+ const isVaultObject = typeof vaultOrAddress === "object" && vaultOrAddress !== null;
259
+ const vault = isVaultObject ? vaultOrAddress : void 0;
260
+ const address = typeof vaultOrAddress === "string" ? vaultOrAddress : void 0;
261
+ const enabled = isVaultObject ? !!vault : !!address && !!chainId;
262
+ const query = useQuery({
263
+ queryKey: isVaultObject ? [
264
+ "earnforge",
265
+ "apyHistory",
266
+ vault?.slug,
267
+ vault?.chainId
268
+ ] : [
269
+ "earnforge",
270
+ "apyHistory",
271
+ address,
272
+ chainId
273
+ ],
274
+ queryFn: () => {
275
+ if (vault) return sdk.getApyHistory(vault);
276
+ return sdk.getApyHistory(address, chainId);
277
+ },
278
+ enabled
279
+ });
280
+ return {
281
+ data: query.data,
282
+ isLoading: query.isLoading,
283
+ error: query.error
284
+ };
285
+ }
286
+ //#endregion
287
+ //#region src/hooks/useEarnDeposit.ts
288
+ const INITIAL_STATE$1 = {
289
+ phase: "idle",
290
+ preflightReport: null,
291
+ allowance: null,
292
+ approvalTx: null,
293
+ quote: null,
294
+ txHash: null,
295
+ error: null
296
+ };
297
+ /**
298
+ * Deposit state machine hook.
299
+ *
300
+ * Flow: idle -> preflight -> quoting -> ready
301
+ * Then call `execute()` to send: ready -> sending -> success
302
+ *
303
+ * ```tsx
304
+ * const { state, prepare, execute, reset } = useEarnDeposit({
305
+ * vault,
306
+ * amount: '100',
307
+ * wallet: address,
308
+ * sendTransactionAsync,
309
+ * });
310
+ * ```
311
+ */
312
+ function useEarnDeposit(params) {
313
+ const sdk = useEarnForge();
314
+ const [state, setState] = useState(INITIAL_STATE$1);
315
+ const abortRef = useRef(false);
316
+ return {
317
+ state,
318
+ prepare: useCallback(async () => {
319
+ if (!params.vault || !params.wallet || !params.amount) {
320
+ setState({
321
+ ...INITIAL_STATE$1,
322
+ phase: "error",
323
+ error: /* @__PURE__ */ new Error("Missing vault, wallet, or amount")
324
+ });
325
+ return;
326
+ }
327
+ abortRef.current = false;
328
+ try {
329
+ setState({
330
+ ...INITIAL_STATE$1,
331
+ phase: "preflight"
332
+ });
333
+ const report = sdk.preflight(params.vault, params.wallet);
334
+ if (abortRef.current) return;
335
+ if (!report.ok) {
336
+ setState({
337
+ ...INITIAL_STATE$1,
338
+ phase: "error",
339
+ preflightReport: report,
340
+ error: /* @__PURE__ */ new Error(`Preflight failed: ${report.issues.map((i) => i.message).join("; ")}`)
341
+ });
342
+ return;
343
+ }
344
+ const fromToken = params.fromToken ?? params.vault.underlyingTokens[0]?.address;
345
+ let allowanceResult = null;
346
+ let approval = null;
347
+ if (params.rpcUrl && fromToken) {
348
+ setState({
349
+ ...INITIAL_STATE$1,
350
+ phase: "checking-allowance",
351
+ preflightReport: report
352
+ });
353
+ const decimals = params.vault.underlyingTokens[0]?.decimals ?? 18;
354
+ const requiredAmount = BigInt(toSmallestUnit(params.amount, decimals));
355
+ allowanceResult = await checkAllowance(params.rpcUrl, fromToken, params.wallet, params.vault.address, requiredAmount);
356
+ if (abortRef.current) return;
357
+ if (!allowanceResult.sufficient) {
358
+ approval = buildApprovalTx(fromToken, params.vault.address, MAX_UINT256, params.vault.chainId);
359
+ setState({
360
+ ...INITIAL_STATE$1,
361
+ phase: "approving",
362
+ preflightReport: report,
363
+ allowance: allowanceResult,
364
+ approvalTx: approval
365
+ });
366
+ const sendFn = params.sendTransactionAsync;
367
+ if (sendFn) {
368
+ await sendFn({
369
+ to: approval.to,
370
+ data: approval.data,
371
+ value: 0n,
372
+ chainId: approval.chainId
373
+ });
374
+ if (abortRef.current) return;
375
+ } else return;
376
+ }
377
+ }
378
+ setState({
379
+ ...INITIAL_STATE$1,
380
+ phase: "quoting",
381
+ preflightReport: report,
382
+ allowance: allowanceResult,
383
+ approvalTx: approval
384
+ });
385
+ const quote = await sdk.buildDepositQuote(params.vault, {
386
+ fromAmount: params.amount,
387
+ wallet: params.wallet,
388
+ fromToken: params.fromToken,
389
+ fromChain: params.fromChain,
390
+ slippage: params.slippage
391
+ });
392
+ if (abortRef.current) return;
393
+ setState({
394
+ ...INITIAL_STATE$1,
395
+ phase: "ready",
396
+ preflightReport: report,
397
+ allowance: allowanceResult,
398
+ approvalTx: approval,
399
+ quote
400
+ });
401
+ } catch (err) {
402
+ if (abortRef.current) return;
403
+ setState({
404
+ ...INITIAL_STATE$1,
405
+ phase: "error",
406
+ error: err instanceof Error ? err : new Error(String(err))
407
+ });
408
+ }
409
+ }, [
410
+ sdk,
411
+ params.vault,
412
+ params.wallet,
413
+ params.amount,
414
+ params.fromToken,
415
+ params.fromChain,
416
+ params.slippage,
417
+ params.rpcUrl,
418
+ params.sendTransactionAsync
419
+ ]),
420
+ execute: useCallback(async () => {
421
+ if (state.phase !== "ready" || !state.quote) {
422
+ setState((prev) => ({
423
+ ...prev,
424
+ phase: "error",
425
+ error: /* @__PURE__ */ new Error("Cannot execute: not in ready state. Call prepare() first.")
426
+ }));
427
+ return;
428
+ }
429
+ const sendFn = params.sendTransactionAsync;
430
+ if (!sendFn) {
431
+ setState((prev) => ({
432
+ ...prev,
433
+ phase: "error",
434
+ error: /* @__PURE__ */ new Error("No sendTransactionAsync provided. Pass it from wagmi useSendTransaction().")
435
+ }));
436
+ return;
437
+ }
438
+ try {
439
+ setState((prev) => ({
440
+ ...prev,
441
+ phase: "sending"
442
+ }));
443
+ const tx = state.quote.quote.transactionRequest;
444
+ const hash = await sendFn({
445
+ to: tx.to,
446
+ data: tx.data,
447
+ value: BigInt(tx.value),
448
+ chainId: tx.chainId
449
+ });
450
+ setState((prev) => ({
451
+ ...prev,
452
+ phase: "success",
453
+ txHash: hash
454
+ }));
455
+ } catch (err) {
456
+ setState((prev) => ({
457
+ ...prev,
458
+ phase: "error",
459
+ error: err instanceof Error ? err : new Error(String(err))
460
+ }));
461
+ }
462
+ }, [
463
+ state.phase,
464
+ state.quote,
465
+ params.sendTransactionAsync
466
+ ]),
467
+ reset: useCallback(() => {
468
+ abortRef.current = true;
469
+ setState(INITIAL_STATE$1);
470
+ }, [])
471
+ };
472
+ }
473
+ //#endregion
474
+ //#region src/hooks/useEarnRedeem.ts
475
+ const INITIAL_STATE = {
476
+ phase: "idle",
477
+ preflightReport: null,
478
+ quote: null,
479
+ txHash: null,
480
+ error: null
481
+ };
482
+ /**
483
+ * Withdrawal/redeem state machine hook.
484
+ *
485
+ * Flow: idle -> preflight -> quoting -> ready
486
+ * Then call `execute()` to send: ready -> sending -> success
487
+ *
488
+ * ```tsx
489
+ * const { state, prepare, execute, reset } = useEarnRedeem({
490
+ * vault,
491
+ * amount: '100',
492
+ * wallet: address,
493
+ * sendTransactionAsync,
494
+ * });
495
+ * ```
496
+ */
497
+ function useEarnRedeem(params) {
498
+ const sdk = useEarnForge();
499
+ const [state, setState] = useState(INITIAL_STATE);
500
+ const abortRef = useRef(false);
501
+ return {
502
+ state,
503
+ prepare: useCallback(async () => {
504
+ if (!params.vault || !params.wallet || !params.amount) {
505
+ setState({
506
+ ...INITIAL_STATE,
507
+ phase: "error",
508
+ error: /* @__PURE__ */ new Error("Missing vault, wallet, or amount")
509
+ });
510
+ return;
511
+ }
512
+ if (!params.vault.isRedeemable) {
513
+ setState({
514
+ ...INITIAL_STATE,
515
+ phase: "error",
516
+ error: /* @__PURE__ */ new Error(`Vault ${params.vault.slug} is not redeemable — withdrawals are not supported.`)
517
+ });
518
+ return;
519
+ }
520
+ abortRef.current = false;
521
+ try {
522
+ setState({
523
+ ...INITIAL_STATE,
524
+ phase: "preflight"
525
+ });
526
+ const report = sdk.preflight(params.vault, params.wallet);
527
+ if (abortRef.current) return;
528
+ if (!report.ok) {
529
+ setState({
530
+ ...INITIAL_STATE,
531
+ phase: "error",
532
+ preflightReport: report,
533
+ error: /* @__PURE__ */ new Error(`Preflight failed: ${report.issues.map((i) => i.message).join("; ")}`)
534
+ });
535
+ return;
536
+ }
537
+ setState({
538
+ ...INITIAL_STATE,
539
+ phase: "quoting",
540
+ preflightReport: report
541
+ });
542
+ const quote = await sdk.buildRedeemQuote(params.vault, {
543
+ fromAmount: params.amount,
544
+ wallet: params.wallet,
545
+ toToken: params.toToken,
546
+ toChain: params.toChain,
547
+ slippage: params.slippage
548
+ });
549
+ if (abortRef.current) return;
550
+ setState({
551
+ ...INITIAL_STATE,
552
+ phase: "ready",
553
+ preflightReport: report,
554
+ quote
555
+ });
556
+ } catch (err) {
557
+ if (abortRef.current) return;
558
+ setState({
559
+ ...INITIAL_STATE,
560
+ phase: "error",
561
+ error: err instanceof Error ? err : new Error(String(err))
562
+ });
563
+ }
564
+ }, [
565
+ sdk,
566
+ params.vault,
567
+ params.wallet,
568
+ params.amount,
569
+ params.toToken,
570
+ params.toChain,
571
+ params.slippage
572
+ ]),
573
+ execute: useCallback(async () => {
574
+ if (state.phase !== "ready" || !state.quote) {
575
+ setState((prev) => ({
576
+ ...prev,
577
+ phase: "error",
578
+ error: /* @__PURE__ */ new Error("Cannot execute: not in ready state. Call prepare() first.")
579
+ }));
580
+ return;
581
+ }
582
+ const sendFn = params.sendTransactionAsync;
583
+ if (!sendFn) {
584
+ setState((prev) => ({
585
+ ...prev,
586
+ phase: "error",
587
+ error: /* @__PURE__ */ new Error("No sendTransactionAsync provided. Pass it from wagmi useSendTransaction().")
588
+ }));
589
+ return;
590
+ }
591
+ try {
592
+ setState((prev) => ({
593
+ ...prev,
594
+ phase: "sending"
595
+ }));
596
+ const tx = state.quote.quote.transactionRequest;
597
+ const hash = await sendFn({
598
+ to: tx.to,
599
+ data: tx.data,
600
+ value: BigInt(tx.value),
601
+ chainId: tx.chainId
602
+ });
603
+ setState((prev) => ({
604
+ ...prev,
605
+ phase: "success",
606
+ txHash: hash
607
+ }));
608
+ } catch (err) {
609
+ setState((prev) => ({
610
+ ...prev,
611
+ phase: "error",
612
+ error: err instanceof Error ? err : new Error(String(err))
613
+ }));
614
+ }
615
+ }, [
616
+ state.phase,
617
+ state.quote,
618
+ params.sendTransactionAsync
619
+ ]),
620
+ reset: useCallback(() => {
621
+ abortRef.current = true;
622
+ setState(INITIAL_STATE);
623
+ }, [])
624
+ };
625
+ }
626
+ //#endregion
627
+ export { EarnForgeContext, EarnForgeProvider, useApyHistory, useEarnDeposit, useEarnForge, useEarnRedeem, useEarnTopYield, usePortfolio, useRiskScore, useStrategy, useSuggest, useVault, useVaults };
628
+
629
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["INITIAL_STATE"],"sources":["../../src/context.ts","../../src/hooks/useVaults.ts","../../src/hooks/useVault.ts","../../src/hooks/useEarnTopYield.ts","../../src/hooks/usePortfolio.ts","../../src/hooks/useRiskScore.ts","../../src/hooks/useStrategy.ts","../../src/hooks/useSuggest.ts","../../src/hooks/useApyHistory.ts","../../src/hooks/useEarnDeposit.ts","../../src/hooks/useEarnRedeem.ts"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\nimport { createContext, useContext, createElement, type ReactNode } from 'react';\nimport type { EarnForge } from '@earnforge/sdk';\n\nconst EarnForgeContext = createContext<EarnForge | null>(null);\n\nexport interface EarnForgeProviderProps {\n sdk: EarnForge;\n children: ReactNode;\n}\n\n/**\n * Wrap your application with `EarnForgeProvider` to make the SDK\n * instance available to all hooks via React context.\n *\n * ```tsx\n * const forge = createEarnForge({ composerApiKey: '...' });\n * <EarnForgeProvider sdk={forge}>\n * <App />\n * </EarnForgeProvider>\n * ```\n */\nexport function EarnForgeProvider({ sdk, children }: EarnForgeProviderProps) {\n return createElement(EarnForgeContext.Provider, { value: sdk }, children);\n}\n\n/**\n * Internal helper — returns the SDK instance from context\n * or throws if used outside an `EarnForgeProvider`.\n */\nexport function useEarnForge(): EarnForge {\n const ctx = useContext(EarnForgeContext);\n if (!ctx) {\n throw new Error(\n 'useEarnForge must be used within an <EarnForgeProvider>. ' +\n 'Wrap your component tree with <EarnForgeProvider sdk={forge}>.',\n );\n }\n return ctx;\n}\n\nexport { EarnForgeContext };\n","// SPDX-License-Identifier: Apache-2.0\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\nimport { useQuery, useQueryClient } from '@tanstack/react-query';\nimport type { Vault, VaultListResponse } from '@earnforge/sdk';\nimport type { StrategyPreset } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UseVaultsParams {\n chainId?: number;\n asset?: string;\n minTvl?: number;\n sortBy?: string;\n limit?: number;\n strategy?: StrategyPreset;\n}\n\nexport interface UseVaultsReturn {\n data: Vault[] | undefined;\n isLoading: boolean;\n error: Error | null;\n fetchMore: () => void;\n hasMore: boolean;\n}\n\n/**\n * Fetch a paginated list of vaults with optional filters.\n * Resets accumulated data when params change.\n *\n * ```tsx\n * const { data, isLoading, fetchMore, hasMore } = useVaults({ chainId: 8453 });\n * ```\n */\nexport function useVaults(params: UseVaultsParams = {}): UseVaultsReturn {\n const sdk = useEarnForge();\n const queryClient = useQueryClient();\n const cursorRef = useRef<string | null>(null);\n const accumulatedRef = useRef<Vault[]>([]);\n\n // Stable serialized params key for comparison\n const paramsKey = useMemo(\n () => JSON.stringify({ chainId: params.chainId, asset: params.asset, minTvl: params.minTvl, sortBy: params.sortBy, strategy: params.strategy }),\n [params.chainId, params.asset, params.minTvl, params.sortBy, params.strategy],\n );\n\n // Reset accumulated data and cursor when params change\n useEffect(() => {\n cursorRef.current = null;\n accumulatedRef.current = [];\n }, [paramsKey]);\n\n const queryKey = useMemo(\n () => ['earnforge', 'vaults', paramsKey, cursorRef.current] as const,\n [paramsKey],\n );\n\n const query = useQuery<VaultListResponse, Error>({\n queryKey,\n queryFn: async () => {\n const result = await sdk.vaults.list({\n chainId: params.chainId,\n asset: params.asset,\n minTvl: params.minTvl,\n sortBy: params.sortBy,\n strategy: params.strategy,\n cursor: cursorRef.current ?? undefined,\n });\n cursorRef.current = result.nextCursor;\n\n if (accumulatedRef.current.length === 0) {\n accumulatedRef.current = result.data;\n } else {\n accumulatedRef.current = [...accumulatedRef.current, ...result.data];\n }\n\n return {\n ...result,\n data: params.limit\n ? accumulatedRef.current.slice(0, params.limit)\n : accumulatedRef.current,\n };\n },\n });\n\n const fetchMore = useCallback(() => {\n if (cursorRef.current) {\n queryClient.invalidateQueries({ queryKey });\n }\n }, [queryClient, queryKey]);\n\n return {\n data: query.data?.data,\n isLoading: query.isLoading,\n error: query.error,\n fetchMore,\n hasMore: cursorRef.current !== null,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useQuery } from '@tanstack/react-query';\nimport type { Vault } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UseVaultReturn {\n data: Vault | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * Fetch a single vault by its slug.\n *\n * ```tsx\n * const { data: vault, isLoading } = useVault('aave-v3-usdc-base');\n * ```\n */\nexport function useVault(slug: string | undefined): UseVaultReturn {\n const sdk = useEarnForge();\n\n const query = useQuery<Vault, Error>({\n queryKey: ['earnforge', 'vault', slug],\n queryFn: () => sdk.vaults.get(slug!),\n enabled: !!slug,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading,\n error: query.error,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useQuery } from '@tanstack/react-query';\nimport type { Vault } from '@earnforge/sdk';\nimport type { StrategyPreset } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UseEarnTopYieldParams {\n asset?: string;\n chainId?: number;\n limit?: number;\n strategy?: StrategyPreset;\n minTvl?: number;\n}\n\nexport interface UseEarnTopYieldReturn {\n data: Vault[] | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * Fetch top-yielding vaults sorted by APY.\n *\n * ```tsx\n * const { data } = useEarnTopYield({ asset: 'USDC', limit: 5 });\n * ```\n */\nexport function useEarnTopYield(params: UseEarnTopYieldParams = {}): UseEarnTopYieldReturn {\n const sdk = useEarnForge();\n\n const query = useQuery<Vault[], Error>({\n queryKey: ['earnforge', 'topYield', params],\n queryFn: () =>\n sdk.vaults.top({\n asset: params.asset,\n chainId: params.chainId,\n limit: params.limit,\n strategy: params.strategy,\n minTvl: params.minTvl,\n }),\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading,\n error: query.error,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useQuery } from '@tanstack/react-query';\nimport type { PortfolioResponse } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UsePortfolioReturn {\n data: PortfolioResponse | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * Fetch portfolio positions for a wallet address.\n *\n * ```tsx\n * const { data } = usePortfolio('0xabc...');\n * ```\n */\nexport function usePortfolio(wallet: string | undefined): UsePortfolioReturn {\n const sdk = useEarnForge();\n\n const query = useQuery<PortfolioResponse, Error>({\n queryKey: ['earnforge', 'portfolio', wallet],\n queryFn: () => sdk.portfolio.get(wallet!),\n enabled: !!wallet,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading,\n error: query.error,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useMemo } from 'react';\nimport type { Vault, RiskScore } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UseRiskScoreReturn {\n data: RiskScore | undefined;\n}\n\n/**\n * Compute a risk score for a vault. This is a synchronous computation\n * wrapped in `useMemo` for referential stability.\n *\n * ```tsx\n * const { data: risk } = useRiskScore(vault);\n * // risk.score, risk.label, risk.breakdown\n * ```\n */\nexport function useRiskScore(vault: Vault | undefined): UseRiskScoreReturn {\n const sdk = useEarnForge();\n\n const data = useMemo(() => {\n if (!vault) return undefined;\n return sdk.riskScore(vault);\n }, [sdk, vault]);\n\n return { data };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useMemo } from 'react';\nimport { getStrategy, type StrategyPreset, type StrategyConfig } from '@earnforge/sdk';\n\nexport interface UseStrategyReturn {\n data: StrategyConfig | undefined;\n filters: StrategyConfig['filters'] | undefined;\n sort: StrategyConfig['sort'] | undefined;\n sortDirection: StrategyConfig['sortDirection'] | undefined;\n}\n\n/**\n * Resolve a strategy preset into its filter configuration.\n * Use the returned `filters` to pass into `useVaults` or `useEarnTopYield`.\n *\n * ```tsx\n * const { filters } = useStrategy('conservative');\n * const { data } = useVaults({ ...filters });\n * ```\n */\nexport function useStrategy(preset: StrategyPreset | undefined): UseStrategyReturn {\n const data = useMemo(() => {\n if (!preset) return undefined;\n return getStrategy(preset);\n }, [preset]);\n\n return {\n data,\n filters: data?.filters,\n sort: data?.sort,\n sortDirection: data?.sortDirection,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useQuery } from '@tanstack/react-query';\nimport type { SuggestResult, StrategyPreset } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UseSuggestParams {\n amount: number;\n asset?: string;\n maxChains?: number;\n strategy?: StrategyPreset;\n}\n\nexport interface UseSuggestReturn {\n data: SuggestResult | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * Get a suggested portfolio allocation based on the given parameters.\n *\n * ```tsx\n * const { data } = useSuggest({ amount: 10_000, asset: 'USDC' });\n * // data.allocations — the recommended split\n * ```\n */\nexport function useSuggest(params: UseSuggestParams | undefined): UseSuggestReturn {\n const sdk = useEarnForge();\n\n const query = useQuery<SuggestResult, Error>({\n queryKey: ['earnforge', 'suggest', params],\n queryFn: () =>\n sdk.suggest({\n amount: params!.amount,\n asset: params!.asset,\n maxChains: params!.maxChains,\n strategy: params!.strategy,\n }),\n enabled: !!params && params.amount > 0,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading,\n error: query.error,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useQuery } from '@tanstack/react-query';\nimport type { ApyDataPoint, Vault } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\nexport interface UseApyHistoryReturn {\n data: ApyDataPoint[] | undefined;\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * Fetch 30-day APY history for a vault from DeFiLlama.\n *\n * Accepts a full Vault object for accurate matching (uses protocol name,\n * chain, underlying tokens, symbol, and TVL proximity). Falls back to\n * the less accurate address+chainId matching when only primitives are given.\n *\n * ```tsx\n * // Preferred: pass the full vault object for accurate DeFiLlama matching\n * const { data: history } = useApyHistory(vault);\n *\n * // Legacy: address + chainId (less accurate matching)\n * const { data: history } = useApyHistory('0xabc...', 8453);\n * ```\n */\nexport function useApyHistory(vault: Vault | undefined): UseApyHistoryReturn;\nexport function useApyHistory(vaultAddress: string | undefined, chainId: number | undefined): UseApyHistoryReturn;\nexport function useApyHistory(\n vaultOrAddress: Vault | string | undefined,\n chainId?: number | undefined,\n): UseApyHistoryReturn {\n const sdk = useEarnForge();\n\n // Determine if we received a Vault object or address+chainId\n const isVaultObject = typeof vaultOrAddress === 'object' && vaultOrAddress !== null;\n const vault = isVaultObject ? (vaultOrAddress as Vault) : undefined;\n const address = typeof vaultOrAddress === 'string' ? vaultOrAddress : undefined;\n\n const enabled = isVaultObject\n ? !!vault\n : !!address && !!chainId;\n\n // Use vault slug + chainId as cache key for vault objects, address + chainId for legacy\n const queryKey = isVaultObject\n ? ['earnforge', 'apyHistory', vault?.slug, vault?.chainId]\n : ['earnforge', 'apyHistory', address, chainId];\n\n const query = useQuery<ApyDataPoint[], Error>({\n queryKey,\n queryFn: () => {\n if (vault) {\n // Full vault object — accurate DeFiLlama matching via protocol+chain+tokens\n return sdk.getApyHistory(vault);\n }\n // Legacy: address + chainId\n return sdk.getApyHistory(address!, chainId!);\n },\n enabled,\n });\n\n return {\n data: query.data,\n isLoading: query.isLoading,\n error: query.error,\n };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useState, useCallback, useRef } from 'react';\nimport type {\n Vault,\n PreflightReport,\n DepositQuoteResult,\n AllowanceResult,\n ApprovalTx,\n} from '@earnforge/sdk';\nimport { checkAllowance, buildApprovalTx, MAX_UINT256, toSmallestUnit } from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\n/**\n * Deposit state machine:\n *\n * idle --> preflight --> checking-allowance --> approving --> quoting --> ready --> sending --> success\n * \\ | | | | | |\n * \\________|_______________|___________________|____________|__________|__________|--> error\n *\n * The \"checking-allowance\" phase verifies the ERC-20 allowance for the fromToken.\n * If allowance is insufficient, \"approving\" sends an approval tx before quoting.\n */\nexport type DepositPhase =\n | 'idle'\n | 'preflight'\n | 'checking-allowance'\n | 'approving'\n | 'quoting'\n | 'ready'\n | 'sending'\n | 'success'\n | 'error';\n\nexport interface DepositState {\n phase: DepositPhase;\n preflightReport: PreflightReport | null;\n allowance: AllowanceResult | null;\n approvalTx: ApprovalTx | null;\n quote: DepositQuoteResult | null;\n txHash: string | null;\n error: Error | null;\n}\n\nexport interface UseEarnDepositParams {\n vault: Vault | undefined;\n amount: string;\n wallet: string;\n fromToken?: string;\n fromChain?: number;\n slippage?: number;\n /** JSON-RPC URL for the source chain — needed for allowance checking */\n rpcUrl?: string;\n /** wagmi's sendTransactionAsync function — pass from useSendTransaction() */\n sendTransactionAsync?: (params: { to: `0x${string}`; data: `0x${string}`; value: bigint; chainId: number }) => Promise<`0x${string}`>;\n}\n\nexport interface UseEarnDepositReturn {\n state: DepositState;\n /** Kick off the preflight -> quote -> ready flow */\n prepare: () => Promise<void>;\n /** Execute the deposit transaction (requires sendTransactionAsync or sendTransaction) */\n execute: () => Promise<void>;\n /** Reset back to idle */\n reset: () => void;\n}\n\nconst INITIAL_STATE: DepositState = {\n phase: 'idle',\n preflightReport: null,\n allowance: null,\n approvalTx: null,\n quote: null,\n txHash: null,\n error: null,\n};\n\n/**\n * Deposit state machine hook.\n *\n * Flow: idle -> preflight -> quoting -> ready\n * Then call `execute()` to send: ready -> sending -> success\n *\n * ```tsx\n * const { state, prepare, execute, reset } = useEarnDeposit({\n * vault,\n * amount: '100',\n * wallet: address,\n * sendTransactionAsync,\n * });\n * ```\n */\nexport function useEarnDeposit(params: UseEarnDepositParams): UseEarnDepositReturn {\n const sdk = useEarnForge();\n const [state, setState] = useState<DepositState>(INITIAL_STATE);\n const abortRef = useRef(false);\n\n const prepare = useCallback(async () => {\n if (!params.vault || !params.wallet || !params.amount) {\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n error: new Error('Missing vault, wallet, or amount'),\n });\n return;\n }\n\n abortRef.current = false;\n\n try {\n // Phase: preflight\n setState({ ...INITIAL_STATE, phase: 'preflight' });\n\n const report = sdk.preflight(params.vault, params.wallet);\n if (abortRef.current) return;\n\n if (!report.ok) {\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n preflightReport: report,\n error: new Error(\n `Preflight failed: ${report.issues.map((i) => i.message).join('; ')}`,\n ),\n });\n return;\n }\n\n // Phase: checking-allowance (if rpcUrl and fromToken are provided)\n const fromToken = params.fromToken ?? params.vault.underlyingTokens[0]?.address;\n let allowanceResult: AllowanceResult | null = null;\n let approval: ApprovalTx | null = null;\n\n if (params.rpcUrl && fromToken) {\n setState({\n ...INITIAL_STATE,\n phase: 'checking-allowance',\n preflightReport: report,\n });\n\n const decimals = params.vault.underlyingTokens[0]?.decimals ?? 18;\n const requiredAmount = BigInt(toSmallestUnit(params.amount, decimals));\n\n // Spender = vault address (Composer routes through vault contract)\n allowanceResult = await checkAllowance(\n params.rpcUrl,\n fromToken,\n params.wallet,\n params.vault.address,\n requiredAmount,\n );\n if (abortRef.current) return;\n\n // If allowance insufficient, build approval tx and wait for it\n if (!allowanceResult.sufficient) {\n approval = buildApprovalTx(\n fromToken,\n params.vault.address,\n MAX_UINT256,\n params.vault.chainId,\n );\n\n setState({\n ...INITIAL_STATE,\n phase: 'approving',\n preflightReport: report,\n allowance: allowanceResult,\n approvalTx: approval,\n });\n\n // Send approval tx if sendTransactionAsync is available\n const sendFn = params.sendTransactionAsync;\n if (sendFn) {\n await sendFn({\n to: approval.to as `0x${string}`,\n data: approval.data as `0x${string}`,\n value: 0n,\n chainId: approval.chainId,\n });\n if (abortRef.current) return;\n } else {\n // Cannot auto-approve without sendTransactionAsync — expose the tx for manual sending\n // The caller should check state.approvalTx and handle it\n return;\n }\n }\n }\n\n // Phase: quoting\n setState({\n ...INITIAL_STATE,\n phase: 'quoting',\n preflightReport: report,\n allowance: allowanceResult,\n approvalTx: approval,\n });\n\n const quote = await sdk.buildDepositQuote(params.vault, {\n fromAmount: params.amount,\n wallet: params.wallet,\n fromToken: params.fromToken,\n fromChain: params.fromChain,\n slippage: params.slippage,\n });\n if (abortRef.current) return;\n\n // Phase: ready\n setState({\n ...INITIAL_STATE,\n phase: 'ready',\n preflightReport: report,\n allowance: allowanceResult,\n approvalTx: approval,\n quote,\n });\n } catch (err) {\n if (abortRef.current) return;\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, [sdk, params.vault, params.wallet, params.amount, params.fromToken, params.fromChain, params.slippage, params.rpcUrl, params.sendTransactionAsync]);\n\n const execute = useCallback(async () => {\n if (state.phase !== 'ready' || !state.quote) {\n setState((prev) => ({\n ...prev,\n phase: 'error',\n error: new Error('Cannot execute: not in ready state. Call prepare() first.'),\n }));\n return;\n }\n\n const sendFn = params.sendTransactionAsync;\n if (!sendFn) {\n setState((prev) => ({\n ...prev,\n phase: 'error',\n error: new Error('No sendTransactionAsync provided. Pass it from wagmi useSendTransaction().'),\n }));\n return;\n }\n\n try {\n setState((prev) => ({ ...prev, phase: 'sending' }));\n\n const tx = state.quote.quote.transactionRequest;\n const hash = await sendFn({\n to: tx.to as `0x${string}`,\n data: tx.data as `0x${string}`,\n value: BigInt(tx.value),\n chainId: tx.chainId,\n });\n\n setState((prev) => ({\n ...prev,\n phase: 'success',\n txHash: hash,\n }));\n } catch (err) {\n setState((prev) => ({\n ...prev,\n phase: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n }));\n }\n }, [state.phase, state.quote, params.sendTransactionAsync]);\n\n const reset = useCallback(() => {\n abortRef.current = true;\n setState(INITIAL_STATE);\n }, []);\n\n return { state, prepare, execute, reset };\n}\n","// SPDX-License-Identifier: Apache-2.0\nimport { useState, useCallback, useRef } from 'react';\nimport type {\n Vault,\n PreflightReport,\n RedeemQuoteResult,\n} from '@earnforge/sdk';\nimport { useEarnForge } from '../context.js';\n\n/**\n * Redeem state machine:\n *\n * idle --> preflight --> quoting --> ready --> sending --> success\n * \\ | | | |\n * \\__________|______________|____________|____________|--> error\n */\nexport type RedeemPhase =\n | 'idle'\n | 'preflight'\n | 'quoting'\n | 'ready'\n | 'sending'\n | 'success'\n | 'error';\n\nexport interface RedeemState {\n phase: RedeemPhase;\n preflightReport: PreflightReport | null;\n quote: RedeemQuoteResult | null;\n txHash: string | null;\n error: Error | null;\n}\n\nexport interface UseEarnRedeemParams {\n vault: Vault | undefined;\n /** Amount of vault share tokens to redeem (human-readable) */\n amount: string;\n wallet: string;\n /** Token to receive. Defaults to underlying token on vault chain. */\n toToken?: string;\n /** Destination chain. Defaults to vault chain. */\n toChain?: number;\n slippage?: number;\n /** wagmi's sendTransactionAsync function — pass from useSendTransaction() */\n sendTransactionAsync?: (params: { to: `0x${string}`; data: `0x${string}`; value: bigint; chainId: number }) => Promise<`0x${string}`>;\n}\n\nexport interface UseEarnRedeemReturn {\n state: RedeemState;\n /** Kick off the preflight -> quote -> ready flow */\n prepare: () => Promise<void>;\n /** Execute the redeem transaction (requires sendTransactionAsync) */\n execute: () => Promise<void>;\n /** Reset back to idle */\n reset: () => void;\n}\n\nconst INITIAL_STATE: RedeemState = {\n phase: 'idle',\n preflightReport: null,\n quote: null,\n txHash: null,\n error: null,\n};\n\n/**\n * Withdrawal/redeem state machine hook.\n *\n * Flow: idle -> preflight -> quoting -> ready\n * Then call `execute()` to send: ready -> sending -> success\n *\n * ```tsx\n * const { state, prepare, execute, reset } = useEarnRedeem({\n * vault,\n * amount: '100',\n * wallet: address,\n * sendTransactionAsync,\n * });\n * ```\n */\nexport function useEarnRedeem(params: UseEarnRedeemParams): UseEarnRedeemReturn {\n const sdk = useEarnForge();\n const [state, setState] = useState<RedeemState>(INITIAL_STATE);\n const abortRef = useRef(false);\n\n const prepare = useCallback(async () => {\n if (!params.vault || !params.wallet || !params.amount) {\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n error: new Error('Missing vault, wallet, or amount'),\n });\n return;\n }\n\n if (!params.vault.isRedeemable) {\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n error: new Error(`Vault ${params.vault.slug} is not redeemable — withdrawals are not supported.`),\n });\n return;\n }\n\n abortRef.current = false;\n\n try {\n // Phase: preflight\n setState({ ...INITIAL_STATE, phase: 'preflight' });\n\n const report = sdk.preflight(params.vault, params.wallet);\n if (abortRef.current) return;\n\n if (!report.ok) {\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n preflightReport: report,\n error: new Error(\n `Preflight failed: ${report.issues.map((i) => i.message).join('; ')}`,\n ),\n });\n return;\n }\n\n // Phase: quoting\n setState({\n ...INITIAL_STATE,\n phase: 'quoting',\n preflightReport: report,\n });\n\n const quote = await sdk.buildRedeemQuote(params.vault, {\n fromAmount: params.amount,\n wallet: params.wallet,\n toToken: params.toToken,\n toChain: params.toChain,\n slippage: params.slippage,\n });\n if (abortRef.current) return;\n\n // Phase: ready\n setState({\n ...INITIAL_STATE,\n phase: 'ready',\n preflightReport: report,\n quote,\n });\n } catch (err) {\n if (abortRef.current) return;\n setState({\n ...INITIAL_STATE,\n phase: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }, [sdk, params.vault, params.wallet, params.amount, params.toToken, params.toChain, params.slippage]);\n\n const execute = useCallback(async () => {\n if (state.phase !== 'ready' || !state.quote) {\n setState((prev) => ({\n ...prev,\n phase: 'error',\n error: new Error('Cannot execute: not in ready state. Call prepare() first.'),\n }));\n return;\n }\n\n const sendFn = params.sendTransactionAsync;\n if (!sendFn) {\n setState((prev) => ({\n ...prev,\n phase: 'error',\n error: new Error('No sendTransactionAsync provided. Pass it from wagmi useSendTransaction().'),\n }));\n return;\n }\n\n try {\n setState((prev) => ({ ...prev, phase: 'sending' }));\n\n const tx = state.quote.quote.transactionRequest;\n const hash = await sendFn({\n to: tx.to as `0x${string}`,\n data: tx.data as `0x${string}`,\n value: BigInt(tx.value),\n chainId: tx.chainId,\n });\n\n setState((prev) => ({\n ...prev,\n phase: 'success',\n txHash: hash,\n }));\n } catch (err) {\n setState((prev) => ({\n ...prev,\n phase: 'error',\n error: err instanceof Error ? err : new Error(String(err)),\n }));\n }\n }, [state.phase, state.quote, params.sendTransactionAsync]);\n\n const reset = useCallback(() => {\n abortRef.current = true;\n setState(INITIAL_STATE);\n }, []);\n\n return { state, prepare, execute, reset };\n}\n"],"mappings":";;;;AAIA,MAAM,mBAAmB,cAAgC,KAAK;;;;;;;;;;;;AAkB9D,SAAgB,kBAAkB,EAAE,KAAK,YAAoC;AAC3E,QAAO,cAAc,iBAAiB,UAAU,EAAE,OAAO,KAAK,EAAE,SAAS;;;;;;AAO3E,SAAgB,eAA0B;CACxC,MAAM,MAAM,WAAW,iBAAiB;AACxC,KAAI,CAAC,IACH,OAAM,IAAI,MACR,0HAED;AAEH,QAAO;;;;;;;;;;;;ACNT,SAAgB,UAAU,SAA0B,EAAE,EAAmB;CACvE,MAAM,MAAM,cAAc;CAC1B,MAAM,cAAc,gBAAgB;CACpC,MAAM,YAAY,OAAsB,KAAK;CAC7C,MAAM,iBAAiB,OAAgB,EAAE,CAAC;CAG1C,MAAM,YAAY,cACV,KAAK,UAAU;EAAE,SAAS,OAAO;EAAS,OAAO,OAAO;EAAO,QAAQ,OAAO;EAAQ,QAAQ,OAAO;EAAQ,UAAU,OAAO;EAAU,CAAC,EAC/I;EAAC,OAAO;EAAS,OAAO;EAAO,OAAO;EAAQ,OAAO;EAAQ,OAAO;EAAS,CAC9E;AAGD,iBAAgB;AACd,YAAU,UAAU;AACpB,iBAAe,UAAU,EAAE;IAC1B,CAAC,UAAU,CAAC;CAEf,MAAM,WAAW,cACT;EAAC;EAAa;EAAU;EAAW,UAAU;EAAQ,EAC3D,CAAC,UAAU,CACZ;CAED,MAAM,QAAQ,SAAmC;EAC/C;EACA,SAAS,YAAY;GACnB,MAAM,SAAS,MAAM,IAAI,OAAO,KAAK;IACnC,SAAS,OAAO;IAChB,OAAO,OAAO;IACd,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,UAAU,OAAO;IACjB,QAAQ,UAAU,WAAW,KAAA;IAC9B,CAAC;AACF,aAAU,UAAU,OAAO;AAE3B,OAAI,eAAe,QAAQ,WAAW,EACpC,gBAAe,UAAU,OAAO;OAEhC,gBAAe,UAAU,CAAC,GAAG,eAAe,SAAS,GAAG,OAAO,KAAK;AAGtE,UAAO;IACL,GAAG;IACH,MAAM,OAAO,QACT,eAAe,QAAQ,MAAM,GAAG,OAAO,MAAM,GAC7C,eAAe;IACpB;;EAEJ,CAAC;CAEF,MAAM,YAAY,kBAAkB;AAClC,MAAI,UAAU,QACZ,aAAY,kBAAkB,EAAE,UAAU,CAAC;IAE5C,CAAC,aAAa,SAAS,CAAC;AAE3B,QAAO;EACL,MAAM,MAAM,MAAM;EAClB,WAAW,MAAM;EACjB,OAAO,MAAM;EACb;EACA,SAAS,UAAU,YAAY;EAChC;;;;;;;;;;;AC7EH,SAAgB,SAAS,MAA0C;CACjE,MAAM,MAAM,cAAc;CAE1B,MAAM,QAAQ,SAAuB;EACnC,UAAU;GAAC;GAAa;GAAS;GAAK;EACtC,eAAe,IAAI,OAAO,IAAI,KAAM;EACpC,SAAS,CAAC,CAAC;EACZ,CAAC;AAEF,QAAO;EACL,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,OAAO,MAAM;EACd;;;;;;;;;;;ACJH,SAAgB,gBAAgB,SAAgC,EAAE,EAAyB;CACzF,MAAM,MAAM,cAAc;CAE1B,MAAM,QAAQ,SAAyB;EACrC,UAAU;GAAC;GAAa;GAAY;GAAO;EAC3C,eACE,IAAI,OAAO,IAAI;GACb,OAAO,OAAO;GACd,SAAS,OAAO;GAChB,OAAO,OAAO;GACd,UAAU,OAAO;GACjB,QAAQ,OAAO;GAChB,CAAC;EACL,CAAC;AAEF,QAAO;EACL,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,OAAO,MAAM;EACd;;;;;;;;;;;AC5BH,SAAgB,aAAa,QAAgD;CAC3E,MAAM,MAAM,cAAc;CAE1B,MAAM,QAAQ,SAAmC;EAC/C,UAAU;GAAC;GAAa;GAAa;GAAO;EAC5C,eAAe,IAAI,UAAU,IAAI,OAAQ;EACzC,SAAS,CAAC,CAAC;EACZ,CAAC;AAEF,QAAO;EACL,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,OAAO,MAAM;EACd;;;;;;;;;;;;;ACbH,SAAgB,aAAa,OAA8C;CACzE,MAAM,MAAM,cAAc;AAO1B,QAAO,EAAE,MALI,cAAc;AACzB,MAAI,CAAC,MAAO,QAAO,KAAA;AACnB,SAAO,IAAI,UAAU,MAAM;IAC1B,CAAC,KAAK,MAAM,CAAC,EAED;;;;;;;;;;;;;ACNjB,SAAgB,YAAY,QAAuD;CACjF,MAAM,OAAO,cAAc;AACzB,MAAI,CAAC,OAAQ,QAAO,KAAA;AACpB,SAAO,YAAY,OAAO;IACzB,CAAC,OAAO,CAAC;AAEZ,QAAO;EACL;EACA,SAAS,MAAM;EACf,MAAM,MAAM;EACZ,eAAe,MAAM;EACtB;;;;;;;;;;;;ACLH,SAAgB,WAAW,QAAwD;CACjF,MAAM,MAAM,cAAc;CAE1B,MAAM,QAAQ,SAA+B;EAC3C,UAAU;GAAC;GAAa;GAAW;GAAO;EAC1C,eACE,IAAI,QAAQ;GACV,QAAQ,OAAQ;GAChB,OAAO,OAAQ;GACf,WAAW,OAAQ;GACnB,UAAU,OAAQ;GACnB,CAAC;EACJ,SAAS,CAAC,CAAC,UAAU,OAAO,SAAS;EACtC,CAAC;AAEF,QAAO;EACL,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,OAAO,MAAM;EACd;;;;ACjBH,SAAgB,cACd,gBACA,SACqB;CACrB,MAAM,MAAM,cAAc;CAG1B,MAAM,gBAAgB,OAAO,mBAAmB,YAAY,mBAAmB;CAC/E,MAAM,QAAQ,gBAAiB,iBAA2B,KAAA;CAC1D,MAAM,UAAU,OAAO,mBAAmB,WAAW,iBAAiB,KAAA;CAEtE,MAAM,UAAU,gBACZ,CAAC,CAAC,QACF,CAAC,CAAC,WAAW,CAAC,CAAC;CAOnB,MAAM,QAAQ,SAAgC;EAC5C,UALe,gBACb;GAAC;GAAa;GAAc,OAAO;GAAM,OAAO;GAAQ,GACxD;GAAC;GAAa;GAAc;GAAS;GAAQ;EAI/C,eAAe;AACb,OAAI,MAEF,QAAO,IAAI,cAAc,MAAM;AAGjC,UAAO,IAAI,cAAc,SAAU,QAAS;;EAE9C;EACD,CAAC;AAEF,QAAO;EACL,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,OAAO,MAAM;EACd;;;;ACCH,MAAMA,kBAA8B;CAClC,OAAO;CACP,iBAAiB;CACjB,WAAW;CACX,YAAY;CACZ,OAAO;CACP,QAAQ;CACR,OAAO;CACR;;;;;;;;;;;;;;;;AAiBD,SAAgB,eAAe,QAAoD;CACjF,MAAM,MAAM,cAAc;CAC1B,MAAM,CAAC,OAAO,YAAY,SAAuBA,gBAAc;CAC/D,MAAM,WAAW,OAAO,MAAM;AAoL9B,QAAO;EAAE;EAAO,SAlLA,YAAY,YAAY;AACtC,OAAI,CAAC,OAAO,SAAS,CAAC,OAAO,UAAU,CAAC,OAAO,QAAQ;AACrD,aAAS;KACP,GAAGA;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,mCAAmC;KACrD,CAAC;AACF;;AAGF,YAAS,UAAU;AAEnB,OAAI;AAEF,aAAS;KAAE,GAAGA;KAAe,OAAO;KAAa,CAAC;IAElD,MAAM,SAAS,IAAI,UAAU,OAAO,OAAO,OAAO,OAAO;AACzD,QAAI,SAAS,QAAS;AAEtB,QAAI,CAAC,OAAO,IAAI;AACd,cAAS;MACP,GAAGA;MACH,OAAO;MACP,iBAAiB;MACjB,uBAAO,IAAI,MACT,qBAAqB,OAAO,OAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,KAAK,KAAK,GACpE;MACF,CAAC;AACF;;IAIF,MAAM,YAAY,OAAO,aAAa,OAAO,MAAM,iBAAiB,IAAI;IACxE,IAAI,kBAA0C;IAC9C,IAAI,WAA8B;AAElC,QAAI,OAAO,UAAU,WAAW;AAC9B,cAAS;MACP,GAAGA;MACH,OAAO;MACP,iBAAiB;MAClB,CAAC;KAEF,MAAM,WAAW,OAAO,MAAM,iBAAiB,IAAI,YAAY;KAC/D,MAAM,iBAAiB,OAAO,eAAe,OAAO,QAAQ,SAAS,CAAC;AAGtE,uBAAkB,MAAM,eACtB,OAAO,QACP,WACA,OAAO,QACP,OAAO,MAAM,SACb,eACD;AACD,SAAI,SAAS,QAAS;AAGtB,SAAI,CAAC,gBAAgB,YAAY;AAC/B,iBAAW,gBACT,WACA,OAAO,MAAM,SACb,aACA,OAAO,MAAM,QACd;AAED,eAAS;OACP,GAAGA;OACH,OAAO;OACP,iBAAiB;OACjB,WAAW;OACX,YAAY;OACb,CAAC;MAGF,MAAM,SAAS,OAAO;AACtB,UAAI,QAAQ;AACV,aAAM,OAAO;QACX,IAAI,SAAS;QACb,MAAM,SAAS;QACf,OAAO;QACP,SAAS,SAAS;QACnB,CAAC;AACF,WAAI,SAAS,QAAS;YAItB;;;AAMN,aAAS;KACP,GAAGA;KACH,OAAO;KACP,iBAAiB;KACjB,WAAW;KACX,YAAY;KACb,CAAC;IAEF,MAAM,QAAQ,MAAM,IAAI,kBAAkB,OAAO,OAAO;KACtD,YAAY,OAAO;KACnB,QAAQ,OAAO;KACf,WAAW,OAAO;KAClB,WAAW,OAAO;KAClB,UAAU,OAAO;KAClB,CAAC;AACF,QAAI,SAAS,QAAS;AAGtB,aAAS;KACP,GAAGA;KACH,OAAO;KACP,iBAAiB;KACjB,WAAW;KACX,YAAY;KACZ;KACD,CAAC;YACK,KAAK;AACZ,QAAI,SAAS,QAAS;AACtB,aAAS;KACP,GAAGA;KACH,OAAO;KACP,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;KAC3D,CAAC;;KAEH;GAAC;GAAK,OAAO;GAAO,OAAO;GAAQ,OAAO;GAAQ,OAAO;GAAW,OAAO;GAAW,OAAO;GAAU,OAAO;GAAQ,OAAO;GAAqB,CAAC;EAoD7H,SAlDT,YAAY,YAAY;AACtC,OAAI,MAAM,UAAU,WAAW,CAAC,MAAM,OAAO;AAC3C,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,4DAA4D;KAC9E,EAAE;AACH;;GAGF,MAAM,SAAS,OAAO;AACtB,OAAI,CAAC,QAAQ;AACX,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,6EAA6E;KAC/F,EAAE;AACH;;AAGF,OAAI;AACF,cAAU,UAAU;KAAE,GAAG;KAAM,OAAO;KAAW,EAAE;IAEnD,MAAM,KAAK,MAAM,MAAM,MAAM;IAC7B,MAAM,OAAO,MAAM,OAAO;KACxB,IAAI,GAAG;KACP,MAAM,GAAG;KACT,OAAO,OAAO,GAAG,MAAM;KACvB,SAAS,GAAG;KACb,CAAC;AAEF,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,QAAQ;KACT,EAAE;YACI,KAAK;AACZ,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;KAC3D,EAAE;;KAEJ;GAAC,MAAM;GAAO,MAAM;GAAO,OAAO;GAAqB,CAAC;EAOzB,OALpB,kBAAkB;AAC9B,YAAS,UAAU;AACnB,YAASA,gBAAc;KACtB,EAAE,CAAC;EAEmC;;;;ACzN3C,MAAM,gBAA6B;CACjC,OAAO;CACP,iBAAiB;CACjB,OAAO;CACP,QAAQ;CACR,OAAO;CACR;;;;;;;;;;;;;;;;AAiBD,SAAgB,cAAc,QAAkD;CAC9E,MAAM,MAAM,cAAc;CAC1B,MAAM,CAAC,OAAO,YAAY,SAAsB,cAAc;CAC9D,MAAM,WAAW,OAAO,MAAM;AA6H9B,QAAO;EAAE;EAAO,SA3HA,YAAY,YAAY;AACtC,OAAI,CAAC,OAAO,SAAS,CAAC,OAAO,UAAU,CAAC,OAAO,QAAQ;AACrD,aAAS;KACP,GAAG;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,mCAAmC;KACrD,CAAC;AACF;;AAGF,OAAI,CAAC,OAAO,MAAM,cAAc;AAC9B,aAAS;KACP,GAAG;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,SAAS,OAAO,MAAM,KAAK,qDAAqD;KAClG,CAAC;AACF;;AAGF,YAAS,UAAU;AAEnB,OAAI;AAEF,aAAS;KAAE,GAAG;KAAe,OAAO;KAAa,CAAC;IAElD,MAAM,SAAS,IAAI,UAAU,OAAO,OAAO,OAAO,OAAO;AACzD,QAAI,SAAS,QAAS;AAEtB,QAAI,CAAC,OAAO,IAAI;AACd,cAAS;MACP,GAAG;MACH,OAAO;MACP,iBAAiB;MACjB,uBAAO,IAAI,MACT,qBAAqB,OAAO,OAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,KAAK,KAAK,GACpE;MACF,CAAC;AACF;;AAIF,aAAS;KACP,GAAG;KACH,OAAO;KACP,iBAAiB;KAClB,CAAC;IAEF,MAAM,QAAQ,MAAM,IAAI,iBAAiB,OAAO,OAAO;KACrD,YAAY,OAAO;KACnB,QAAQ,OAAO;KACf,SAAS,OAAO;KAChB,SAAS,OAAO;KAChB,UAAU,OAAO;KAClB,CAAC;AACF,QAAI,SAAS,QAAS;AAGtB,aAAS;KACP,GAAG;KACH,OAAO;KACP,iBAAiB;KACjB;KACD,CAAC;YACK,KAAK;AACZ,QAAI,SAAS,QAAS;AACtB,aAAS;KACP,GAAG;KACH,OAAO;KACP,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;KAC3D,CAAC;;KAEH;GAAC;GAAK,OAAO;GAAO,OAAO;GAAQ,OAAO;GAAQ,OAAO;GAAS,OAAO;GAAS,OAAO;GAAS,CAAC;EAoD7E,SAlDT,YAAY,YAAY;AACtC,OAAI,MAAM,UAAU,WAAW,CAAC,MAAM,OAAO;AAC3C,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,4DAA4D;KAC9E,EAAE;AACH;;GAGF,MAAM,SAAS,OAAO;AACtB,OAAI,CAAC,QAAQ;AACX,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,uBAAO,IAAI,MAAM,6EAA6E;KAC/F,EAAE;AACH;;AAGF,OAAI;AACF,cAAU,UAAU;KAAE,GAAG;KAAM,OAAO;KAAW,EAAE;IAEnD,MAAM,KAAK,MAAM,MAAM,MAAM;IAC7B,MAAM,OAAO,MAAM,OAAO;KACxB,IAAI,GAAG;KACP,MAAM,GAAG;KACT,OAAO,OAAO,GAAG,MAAM;KACvB,SAAS,GAAG;KACb,CAAC;AAEF,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,QAAQ;KACT,EAAE;YACI,KAAK;AACZ,cAAU,UAAU;KAClB,GAAG;KACH,OAAO;KACP,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;KAC3D,EAAE;;KAEJ;GAAC,MAAM;GAAO,MAAM;GAAO,OAAO;GAAqB,CAAC;EAOzB,OALpB,kBAAkB;AAC9B,YAAS,UAAU;AACnB,YAAS,cAAc;KACtB,EAAE,CAAC;EAEmC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@earnforge/react",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "Apache-2.0",
6
+ "description": "React hooks for the LI.FI Earn API — vault discovery, risk scoring, yield strategies, and deposits",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/esm/index.js",
10
+ "types": "./dist/esm/index.d.ts"
11
+ }
12
+ },
13
+ "files": ["dist", "README.md", "LICENSE"],
14
+ "scripts": {
15
+ "build": "tsdown src/index.ts --format esm --dts --out-dir dist/esm",
16
+ "typecheck": "tsc --noEmit",
17
+ "test": "vitest run",
18
+ "test:unit": "vitest run",
19
+ "clean": "rm -rf dist .turbo"
20
+ },
21
+ "dependencies": {
22
+ "@earnforge/sdk": "workspace:*"
23
+ },
24
+ "peerDependencies": {
25
+ "@tanstack/react-query": ">=5.90.0",
26
+ "react": ">=18",
27
+ "viem": "^2.47.11",
28
+ "wagmi": ">=2.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@tanstack/react-query": "^5.90.0",
32
+ "@testing-library/react": "^16.3.0",
33
+ "jsdom": "^26.1.0",
34
+ "react": "^19.2.5",
35
+ "react-dom": "^19.2.5",
36
+ "tsdown": "^0.21.7",
37
+ "typescript": "^5.9.3",
38
+ "vitest": "^4.1.4"
39
+ }
40
+ }