pods-sdk 0.2.58

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 (194) hide show
  1. package/README.md +760 -0
  2. package/dist/api/actions.api.d.ts +433 -0
  3. package/dist/api/actions.api.d.ts.map +1 -0
  4. package/dist/api/history.api.d.ts +311 -0
  5. package/dist/api/history.api.d.ts.map +1 -0
  6. package/dist/api/tokens.api.d.ts +985 -0
  7. package/dist/api/tokens.api.d.ts.map +1 -0
  8. package/dist/components/earn/GroupedStrategyList.d.ts +21 -0
  9. package/dist/components/earn/GroupedStrategyList.d.ts.map +1 -0
  10. package/dist/components/earn/StrategyDetailsView.d.ts +14 -0
  11. package/dist/components/earn/StrategyDetailsView.d.ts.map +1 -0
  12. package/dist/components/earn/desktop/EarnPageDesktop.d.ts +13 -0
  13. package/dist/components/earn/desktop/EarnPageDesktop.d.ts.map +1 -0
  14. package/dist/components/earn/desktop/ExploreStrategiesGrid.d.ts +30 -0
  15. package/dist/components/earn/desktop/ExploreStrategiesGrid.d.ts.map +1 -0
  16. package/dist/components/earn/desktop/InvestedStrategiesSection.d.ts +22 -0
  17. package/dist/components/earn/desktop/InvestedStrategiesSection.d.ts.map +1 -0
  18. package/dist/components/earn/desktop/InvestmentSummaryDesktop.d.ts +27 -0
  19. package/dist/components/earn/desktop/InvestmentSummaryDesktop.d.ts.map +1 -0
  20. package/dist/components/earn/desktop/RecentTransactions.d.ts +32 -0
  21. package/dist/components/earn/desktop/RecentTransactions.d.ts.map +1 -0
  22. package/dist/components/earn/desktop/StrategyGridCard.d.ts +35 -0
  23. package/dist/components/earn/desktop/StrategyGridCard.d.ts.map +1 -0
  24. package/dist/constants/analytics.d.ts +92 -0
  25. package/dist/constants/analytics.d.ts.map +1 -0
  26. package/dist/constants/error-monitoring.d.ts +2 -0
  27. package/dist/constants/error-monitoring.d.ts.map +1 -0
  28. package/dist/domain/swap/deriveAmountInForSwap.d.ts +11 -0
  29. package/dist/domain/swap/deriveAmountInForSwap.d.ts.map +1 -0
  30. package/dist/domain/swap/deriveTokenPriceUSD.d.ts +10 -0
  31. package/dist/domain/swap/deriveTokenPriceUSD.d.ts.map +1 -0
  32. package/dist/domain/swap/getAmountInUSD.d.ts +12 -0
  33. package/dist/domain/swap/getAmountInUSD.d.ts.map +1 -0
  34. package/dist/domain/swap/getQuoteOutputUI.d.ts +14 -0
  35. package/dist/domain/swap/getQuoteOutputUI.d.ts.map +1 -0
  36. package/dist/domain/swap/getQuoteOutputUSD.d.ts +12 -0
  37. package/dist/domain/swap/getQuoteOutputUSD.d.ts.map +1 -0
  38. package/dist/domain/swap/index.d.ts +11 -0
  39. package/dist/domain/swap/index.d.ts.map +1 -0
  40. package/dist/domain/swap/isPositiveNumberString.d.ts +5 -0
  41. package/dist/domain/swap/isPositiveNumberString.d.ts.map +1 -0
  42. package/dist/domain/swap/isQuoteMatchingInput.d.ts +24 -0
  43. package/dist/domain/swap/isQuoteMatchingInput.d.ts.map +1 -0
  44. package/dist/domain/swap/normalizeSwapAddress.d.ts +6 -0
  45. package/dist/domain/swap/normalizeSwapAddress.d.ts.map +1 -0
  46. package/dist/domain/swap/resolveEffectivePrice.d.ts +14 -0
  47. package/dist/domain/swap/resolveEffectivePrice.d.ts.map +1 -0
  48. package/dist/domain/swap/resolveInputAmountBase.d.ts +11 -0
  49. package/dist/domain/swap/resolveInputAmountBase.d.ts.map +1 -0
  50. package/dist/hooks/useAnalytics.d.ts +9 -0
  51. package/dist/hooks/useAnalytics.d.ts.map +1 -0
  52. package/dist/hooks/useDimensions.d.ts +15 -0
  53. package/dist/hooks/useDimensions.d.ts.map +1 -0
  54. package/dist/hooks/useGlobalCurrency.d.ts +17 -0
  55. package/dist/hooks/useGlobalCurrency.d.ts.map +1 -0
  56. package/dist/hooks/useGlobalHistory.d.ts +22 -0
  57. package/dist/hooks/useGlobalHistory.d.ts.map +1 -0
  58. package/dist/hooks/useGroupedStrategies.d.ts +4 -0
  59. package/dist/hooks/useGroupedStrategies.d.ts.map +1 -0
  60. package/dist/hooks/useI18n.d.ts +12 -0
  61. package/dist/hooks/useI18n.d.ts.map +1 -0
  62. package/dist/hooks/useStrategyTokens.d.ts +15 -0
  63. package/dist/hooks/useStrategyTokens.d.ts.map +1 -0
  64. package/dist/hooks/useSwapFlowLogic.d.ts +198 -0
  65. package/dist/hooks/useSwapFlowLogic.d.ts.map +1 -0
  66. package/dist/hooks/useTokenGroups.d.ts +14 -0
  67. package/dist/hooks/useTokenGroups.d.ts.map +1 -0
  68. package/dist/i18n/index.d.ts +13 -0
  69. package/dist/i18n/index.d.ts.map +1 -0
  70. package/dist/i18n/messages.d.ts +307 -0
  71. package/dist/i18n/messages.d.ts.map +1 -0
  72. package/dist/pages/SwapFlow/SwapFormContext.d.ts +6 -0
  73. package/dist/pages/SwapFlow/SwapFormContext.d.ts.map +1 -0
  74. package/dist/pages/SwapFlow/SwapHistoryScreen.d.ts +4 -0
  75. package/dist/pages/SwapFlow/SwapHistoryScreen.d.ts.map +1 -0
  76. package/dist/pages/TransactionProcessingDetails/StepDisplay.d.ts +10 -0
  77. package/dist/pages/TransactionProcessingDetails/StepDisplay.d.ts.map +1 -0
  78. package/dist/pages/TransactionProcessingDetails/StepStatusIcon.d.ts +11 -0
  79. package/dist/pages/TransactionProcessingDetails/StepStatusIcon.d.ts.map +1 -0
  80. package/dist/pages/TransactionProcessingDetails/StepStatusText.d.ts +10 -0
  81. package/dist/pages/TransactionProcessingDetails/StepStatusText.d.ts.map +1 -0
  82. package/dist/pages/TransactionProcessingDetails/index.d.ts +4 -0
  83. package/dist/pages/TransactionProcessingDetails/index.d.ts.map +1 -0
  84. package/dist/pages/TransactionProcessingDetails.d.ts +22 -0
  85. package/dist/pages/TransactionProcessingDetails.d.ts.map +1 -0
  86. package/dist/pages/TransactionStepValue.d.ts +12 -0
  87. package/dist/pages/TransactionStepValue.d.ts.map +1 -0
  88. package/dist/services/analyticsService.d.ts +11 -0
  89. package/dist/services/analyticsService.d.ts.map +1 -0
  90. package/dist/services/errorMonitoringService.d.ts +17 -0
  91. package/dist/services/errorMonitoringService.d.ts.map +1 -0
  92. package/dist/services/scrubPii.d.ts +3 -0
  93. package/dist/services/scrubPii.d.ts.map +1 -0
  94. package/dist/test-utils/grouped-strategies-dummy.d.ts +6 -0
  95. package/dist/test-utils/grouped-strategies-dummy.d.ts.map +1 -0
  96. package/dist/test-utils/history-dummy.d.ts +34 -0
  97. package/dist/test-utils/history-dummy.d.ts.map +1 -0
  98. package/dist/test-utils/investment-summary-dummy.d.ts +17 -0
  99. package/dist/test-utils/investment-summary-dummy.d.ts.map +1 -0
  100. package/dist/test-utils/strategies-dummy.d.ts +8 -0
  101. package/dist/test-utils/strategies-dummy.d.ts.map +1 -0
  102. package/dist/test-utils/strategies-with-apy-dummy.d.ts +32 -0
  103. package/dist/test-utils/strategies-with-apy-dummy.d.ts.map +1 -0
  104. package/dist/test-utils/swap-dummy.d.ts +35 -0
  105. package/dist/test-utils/swap-dummy.d.ts.map +1 -0
  106. package/dist/test-utils/swap-form-view-dummy.d.ts +21 -0
  107. package/dist/test-utils/swap-form-view-dummy.d.ts.map +1 -0
  108. package/dist/types/analytics.d.ts +17 -0
  109. package/dist/types/analytics.d.ts.map +1 -0
  110. package/dist/types/currency.d.ts +2 -0
  111. package/dist/types/currency.d.ts.map +1 -0
  112. package/dist/types/dimensions.d.ts +7 -0
  113. package/dist/types/dimensions.d.ts.map +1 -0
  114. package/dist/types/grouped-strategies.d.ts +42 -0
  115. package/dist/types/grouped-strategies.d.ts.map +1 -0
  116. package/dist/types/sdk-error-context.d.ts +10 -0
  117. package/dist/types/sdk-error-context.d.ts.map +1 -0
  118. package/dist/types/strategy-with-apy.d.ts +8 -0
  119. package/dist/types/strategy-with-apy.d.ts.map +1 -0
  120. package/dist/types/tokengroups.d.ts +47 -0
  121. package/dist/types/tokengroups.d.ts.map +1 -0
  122. package/dist/types/transaction.d.ts +14 -0
  123. package/dist/types/transaction.d.ts.map +1 -0
  124. package/dist/ui/action-sheet/ChooseAStrategyActionsheetView.d.ts +14 -0
  125. package/dist/ui/action-sheet/ChooseAStrategyActionsheetView.d.ts.map +1 -0
  126. package/dist/ui/action-sheet/ChooseWithdrawAssetActionsheet.d.ts +16 -0
  127. package/dist/ui/action-sheet/ChooseWithdrawAssetActionsheet.d.ts.map +1 -0
  128. package/dist/ui/chip/Chip.d.ts +30 -0
  129. package/dist/ui/chip/Chip.d.ts.map +1 -0
  130. package/dist/ui/chip/ChipGroup.d.ts +43 -0
  131. package/dist/ui/chip/ChipGroup.d.ts.map +1 -0
  132. package/dist/ui/chip/index.d.ts +5 -0
  133. package/dist/ui/chip/index.d.ts.map +1 -0
  134. package/dist/ui/group-label/GroupLabel.d.ts +17 -0
  135. package/dist/ui/group-label/GroupLabel.d.ts.map +1 -0
  136. package/dist/ui/group-label/index.d.ts +3 -0
  137. package/dist/ui/group-label/index.d.ts.map +1 -0
  138. package/dist/ui/loading/LoadingDots.d.ts +11 -0
  139. package/dist/ui/loading/LoadingDots.d.ts.map +1 -0
  140. package/dist/ui/loading/index.d.ts +2 -0
  141. package/dist/ui/loading/index.d.ts.map +1 -0
  142. package/dist/ui/swap-form/SwapAdvancedSettings.d.ts +9 -0
  143. package/dist/ui/swap-form/SwapAdvancedSettings.d.ts.map +1 -0
  144. package/dist/ui/swap-form/SwapAmountInputView.d.ts +11 -0
  145. package/dist/ui/swap-form/SwapAmountInputView.d.ts.map +1 -0
  146. package/dist/ui/swap-form/SwapNetworkSelectorView.d.ts +10 -0
  147. package/dist/ui/swap-form/SwapNetworkSelectorView.d.ts.map +1 -0
  148. package/dist/ui/swap-form/SwapOutputAmountView.d.ts +8 -0
  149. package/dist/ui/swap-form/SwapOutputAmountView.d.ts.map +1 -0
  150. package/dist/ui/swap-form/SwapQuoteBlockchainCostsView.d.ts +9 -0
  151. package/dist/ui/swap-form/SwapQuoteBlockchainCostsView.d.ts.map +1 -0
  152. package/dist/ui/swap-form/SwapQuoteErrorsView.d.ts +7 -0
  153. package/dist/ui/swap-form/SwapQuoteErrorsView.d.ts.map +1 -0
  154. package/dist/ui/swap-form/SwapQuoteHeaderView.d.ts +7 -0
  155. package/dist/ui/swap-form/SwapQuoteHeaderView.d.ts.map +1 -0
  156. package/dist/ui/swap-form/SwapSlippageToleranceButtonsView.d.ts +7 -0
  157. package/dist/ui/swap-form/SwapSlippageToleranceButtonsView.d.ts.map +1 -0
  158. package/dist/ui/swap-form/SwapTokenSelectorView.d.ts +11 -0
  159. package/dist/ui/swap-form/SwapTokenSelectorView.d.ts.map +1 -0
  160. package/dist/ui/swap-form/SwapTransactionDetails.d.ts +6 -0
  161. package/dist/ui/swap-form/SwapTransactionDetails.d.ts.map +1 -0
  162. package/dist/ui/transaction-screen/history/HistoryDepositDetailsView.d.ts +25 -0
  163. package/dist/ui/transaction-screen/history/HistoryDepositDetailsView.d.ts.map +1 -0
  164. package/dist/ui/transaction-screen/history/HistoryDetailsNotFound.d.ts +5 -0
  165. package/dist/ui/transaction-screen/history/HistoryDetailsNotFound.d.ts.map +1 -0
  166. package/dist/ui/transaction-screen/history/HistorySwapDetailsScreen.d.ts +8 -0
  167. package/dist/ui/transaction-screen/history/HistorySwapDetailsScreen.d.ts.map +1 -0
  168. package/dist/ui/transaction-screen/history/HistoryWithdrawDetailsView.d.ts +5 -0
  169. package/dist/ui/transaction-screen/history/HistoryWithdrawDetailsView.d.ts.map +1 -0
  170. package/dist/ui/transaction-screen/swap/SwapCrossChainProcessingScreen.d.ts +3 -0
  171. package/dist/ui/transaction-screen/swap/SwapCrossChainProcessingScreen.d.ts.map +1 -0
  172. package/dist/ui/transaction-screen/withdraw/WithdrawSuccess.d.ts +24 -0
  173. package/dist/ui/transaction-screen/withdraw/WithdrawSuccess.d.ts.map +1 -0
  174. package/dist/utils/addressUtils.d.ts +7 -0
  175. package/dist/utils/addressUtils.d.ts.map +1 -0
  176. package/dist/utils/analytics.d.ts +5 -0
  177. package/dist/utils/analytics.d.ts.map +1 -0
  178. package/dist/utils/currency.d.ts +11 -0
  179. package/dist/utils/currency.d.ts.map +1 -0
  180. package/dist/utils/errorMapping.d.ts +19 -0
  181. package/dist/utils/errorMapping.d.ts.map +1 -0
  182. package/dist/utils/filterStrategies.d.ts +21 -0
  183. package/dist/utils/filterStrategies.d.ts.map +1 -0
  184. package/dist/utils/fontLoader.d.ts +9 -0
  185. package/dist/utils/fontLoader.d.ts.map +1 -0
  186. package/dist/utils/historyMappers.d.ts +71 -0
  187. package/dist/utils/historyMappers.d.ts.map +1 -0
  188. package/dist/utils/strategyCategories.d.ts +25 -0
  189. package/dist/utils/strategyCategories.d.ts.map +1 -0
  190. package/dist/utils/tokenSorting.d.ts +30 -0
  191. package/dist/utils/tokenSorting.d.ts.map +1 -0
  192. package/dist/utils/tokengroups.d.ts +11 -0
  193. package/dist/utils/tokengroups.d.ts.map +1 -0
  194. package/package.json +132 -0
package/README.md ADDED
@@ -0,0 +1,760 @@
1
+ # Deframe SDK
2
+
3
+ React widgets for DeFi earn and swap flows
4
+
5
+ This package ships two host-rendered widgets:
6
+ - `EarnWidget`
7
+ - `SwapWidget`
8
+
9
+ The host application owns wallet connection, signing, and transaction submission through `processBytecode`.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ # pnpm
15
+ pnpm add deframe-sdk
16
+ # npm
17
+ npm install deframe-sdk
18
+ # yarn
19
+ yarn add deframe-sdk
20
+ ```
21
+
22
+ Notes:
23
+ - Use only the production npm package: `deframe-sdk` ([npm](https://www.npmjs.com/package/deframe-sdk)).
24
+ - No local/workspace/file dependency references are required for host integration.
25
+ - Keep `react` and `react-dom` installed in the host app.
26
+ - `deframe-sdk` loads widget styles from its entrypoint. No separate CSS import is required for the default setup.
27
+
28
+ ## Vite: Single React Instance (important for linked/local packages)
29
+
30
+ If your app consumes SDK packages via `file:`, workspace links, or symlinks, multiple React copies can be resolved at runtime.
31
+ That can cause `Invalid hook call` errors (for example: `Cannot read properties of null (reading 'useEffect')`).
32
+
33
+ Use this Vite config to force one React instance across app + linked packages:
34
+
35
+ ```ts
36
+ import path from 'node:path'
37
+ import { defineConfig } from 'vite'
38
+ import react from '@vitejs/plugin-react'
39
+
40
+ export default defineConfig({
41
+ plugins: [react()],
42
+ resolve: {
43
+ dedupe: ['react', 'react-dom'],
44
+ alias: {
45
+ react: path.resolve(__dirname, 'node_modules/react'),
46
+ 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),
47
+ 'react/jsx-runtime': path.resolve(__dirname, 'node_modules/react/jsx-runtime.js'),
48
+ 'react/jsx-dev-runtime': path.resolve(__dirname, 'node_modules/react/jsx-dev-runtime.js'),
49
+ },
50
+ },
51
+ optimizeDeps: {
52
+ // Avoid manual .vite cache cleanup in linked-package setups.
53
+ force: true,
54
+ },
55
+ })
56
+ ```
57
+
58
+ With this config in place, you should not need manual `rm -rf node_modules/.vite` or manual restart instructions in your integration flow.
59
+
60
+ ## CSS Isolation (Host Shell vs Widget)
61
+
62
+ The SDK widgets are designed to be embedded into existing apps without taking over host styling.
63
+
64
+ Use this isolation model:
65
+
66
+ - Keep host/shell styles scoped to your own container (example: `.host-shell ...`).
67
+ - Treat `.deframe-widget` as a style boundary owned by the SDK.
68
+ - Avoid global resets that can leak into third-party widgets:
69
+ - `* { ... }`
70
+ - `div, button, input { ... }`
71
+ - global `all: initial` / aggressive normalize rules on app-wide containers.
72
+ - Use `DeframeProvider` `config.theme` as the source of truth for widget theme (`mode`, `preset`, `overrides`).
73
+ - Do not rely on ad-hoc utility-class overrides inside widget internals except as temporary debug workarounds.
74
+
75
+ Recommended host layout:
76
+
77
+ ```tsx
78
+ <main className="host-shell">
79
+ {/* host UI */}
80
+ <section className="widget-slot">
81
+ <EarnWidget autoHeight />
82
+ </section>
83
+ </main>
84
+ ```
85
+
86
+ ```css
87
+ .host-shell {
88
+ /* your app styles */
89
+ }
90
+
91
+ .widget-slot {
92
+ /* spacing, border, layout only */
93
+ }
94
+ ```
95
+
96
+ Reference widget-only variable block (generic dark/default preset, client-agnostic):
97
+
98
+ ```css
99
+ /* Scope to widget only. Do not apply globally. */
100
+ .host-shell .deframe-widget {
101
+ --deframe-brand-primary: #405eff;
102
+ --deframe-brand-secondary: #a9abf7;
103
+ --deframe-bg-default: #121212;
104
+ --deframe-bg-subtle: #1e1e1e;
105
+ --deframe-bg-muted: #2c2c2c;
106
+ --deframe-bg-raised: #232323;
107
+ --deframe-bg-inverse: #ffffff;
108
+ --deframe-text-primary: #ffffff;
109
+ --deframe-text-secondary: #e3e4e8;
110
+ --deframe-text-disabled: #898d95;
111
+ --deframe-text-inverse: #252050;
112
+ --deframe-state-success: #2ba176;
113
+ --deframe-state-error: #ff4d4f;
114
+ --deframe-state-warning: #f6a700;
115
+
116
+ /* Important fallbacks to avoid light cards in dark mode */
117
+ --color-bg-raised: var(--deframe-bg-raised, #232323);
118
+ --color-brand-tint: #1e1e3f;
119
+ }
120
+ ```
121
+
122
+ Generic preset recommendation:
123
+
124
+ ```ts
125
+ theme: {
126
+ mode: 'dark',
127
+ preset: 'default',
128
+ }
129
+ ```
130
+
131
+ Use `preset: 'cryptocontrol'` only when you intentionally want that brand style.
132
+
133
+ If you need hard guarantees in high-risk host environments, use one of:
134
+
135
+ - Dedicated iframe container for the widget.
136
+ - Shadow DOM boundary around the widget mount point.
137
+
138
+ ## Environment Variables
139
+
140
+ ```bash
141
+ NEXT_PUBLIC_DEFRAME_API_URL=https://api.deframe.com
142
+ NEXT_PUBLIC_DEFRAME_API_KEY=your_deframe_api_key
143
+ ```
144
+
145
+ Canonical env forms for host integrations:
146
+ - public client:
147
+ - `NEXT_PUBLIC_DEFRAME_API_URL`
148
+ - `NEXT_PUBLIC_DEFRAME_API_KEY`
149
+ - server/internal:
150
+ - `DEFRAME_API_URL`
151
+ - `DEFRAME_API_KEY`
152
+ - if API URL is not set in some internal hosts, default to `https://api.deframe.com` (where applicable).
153
+
154
+ ## Core Integration
155
+
156
+ ### 1) Wrap your widget tree with `DeframeProvider`
157
+
158
+ ```tsx
159
+ 'use client'
160
+
161
+ import { ReactNode, useMemo } from 'react'
162
+ import { DeframeProvider, type UpdateTxStatus } from 'deframe-sdk'
163
+
164
+ type BytecodeTransaction = {
165
+ chainId?: number
166
+ to: string
167
+ data: string
168
+ value: string
169
+ gasLimit?: string
170
+ }
171
+
172
+ type ProcessBytecode = (
173
+ payload: { clientTxId: string; bytecodes: BytecodeTransaction[]; simulateError?: boolean },
174
+ ctx: { updateTxStatus: UpdateTxStatus }
175
+ ) => void | Promise<void>
176
+
177
+ export function DeframeHostProvider({
178
+ children,
179
+ walletAddress,
180
+ userId,
181
+ globalCurrency,
182
+ globalCurrencyExchangeRate,
183
+ processBytecode,
184
+ }: {
185
+ children: ReactNode
186
+ walletAddress: string
187
+ userId?: string
188
+ globalCurrency?: 'USD' | 'BRL'
189
+ globalCurrencyExchangeRate?: number
190
+ processBytecode: ProcessBytecode
191
+ }) {
192
+ const config = useMemo(() => ({
193
+ DEFRAME_API_URL: process.env.NEXT_PUBLIC_DEFRAME_API_URL,
194
+ DEFRAME_API_KEY: process.env.NEXT_PUBLIC_DEFRAME_API_KEY,
195
+ walletAddress,
196
+ userId,
197
+ globalCurrency,
198
+ globalCurrencyExchangeRate,
199
+ strategiesLimit: 50,
200
+ debug: process.env.NODE_ENV !== 'production',
201
+ theme: {
202
+ mode: 'dark' as const,
203
+ preset: 'cryptocontrol' as const,
204
+ },
205
+ }), [walletAddress, userId, globalCurrency, globalCurrencyExchangeRate])
206
+
207
+ return (
208
+ <DeframeProvider config={config} processBytecode={processBytecode}>
209
+ {children}
210
+ </DeframeProvider>
211
+ )
212
+ }
213
+ ```
214
+
215
+ ### 2) Render `EarnWidget`
216
+
217
+ ```tsx
218
+ 'use client'
219
+
220
+ import { useState } from 'react'
221
+ import { EarnWidget } from 'deframe-sdk'
222
+
223
+ export function EarnPage() {
224
+ const [routeName, setRouteName] = useState('overview')
225
+ const isOverview = routeName === 'overview'
226
+
227
+ return (
228
+ <div className={`w-full mx-auto ${isOverview ? 'lg:p-12' : 'lg:p-6'}`}>
229
+ <div className={`w-full mx-auto ${isOverview ? 'max-w-[1400px]' : 'max-w-[620px]'}`}>
230
+ <EarnWidget autoHeight onRouteChange={setRouteName} />
231
+ </div>
232
+ </div>
233
+ )
234
+ }
235
+ ```
236
+
237
+ ### 3) Render `SwapWidget` with optional prefilled params
238
+
239
+ ```tsx
240
+ 'use client'
241
+
242
+ import { useMemo } from 'react'
243
+ import { useSearchParams } from 'next/navigation'
244
+ import { SwapWidget } from 'deframe-sdk'
245
+
246
+ export function SwapPage() {
247
+ const searchParams = useSearchParams()
248
+
249
+ const toTokenAddress = searchParams.get('toTokenAddress') ?? undefined
250
+ const toChainId = searchParams.get('toChainId') ? Number(searchParams.get('toChainId')) : undefined
251
+ const fromTokenAddress = searchParams.get('fromTokenAddress') ?? undefined
252
+ const fromChainId = searchParams.get('fromChainId') ? Number(searchParams.get('fromChainId')) : undefined
253
+
254
+ const widgetProps = useMemo(() => {
255
+ const props: {
256
+ height: string
257
+ toTokenAddress?: string
258
+ toChainId?: number
259
+ fromTokenAddress?: string
260
+ fromChainId?: number
261
+ } = {
262
+ height: '800px',
263
+ }
264
+
265
+ if (toTokenAddress) props.toTokenAddress = toTokenAddress
266
+ if (toChainId) props.toChainId = toChainId
267
+ if (fromTokenAddress) props.fromTokenAddress = fromTokenAddress
268
+ if (fromChainId) props.fromChainId = fromChainId
269
+
270
+ return props
271
+ }, [toTokenAddress, toChainId, fromTokenAddress, fromChainId])
272
+
273
+ const widgetKey = `${toTokenAddress}-${toChainId}-${fromTokenAddress}-${fromChainId}`
274
+
275
+ return <SwapWidget key={widgetKey} {...widgetProps} />
276
+ }
277
+ ```
278
+
279
+ ## Widget-to-Host Events
280
+ This README keeps the working route pattern loop-safe for existing Privy-based implementations:
281
+
282
+ Use `EarnWidget` `onRouteChange` prop to keep lightweight host routing state:
283
+ - `history` -> `/dashboard/history`
284
+ - `wallet` -> `/dashboard`
285
+ - `swap` -> `/dashboard/swap`
286
+ - `earn` -> `/dashboard/earn`
287
+
288
+ `useDeframe().addEventListener` route handlers are intentionally omitted here because they caused host loops in some integrations.
289
+
290
+ ## `processBytecode` contract
291
+
292
+ The host must execute `bytecodes` and report lifecycle updates with `ctx.updateTxStatus(...)`.
293
+
294
+ Payload shape is:
295
+
296
+ ```ts
297
+ type TxIntent = {
298
+ clientTxId: string
299
+ bytecodes: Array<{ chainId?: number; to: string; data: string; value: string; gasLimit?: string }>
300
+ simulateError?: boolean
301
+ }
302
+ ```
303
+
304
+ ### Required success path statuses
305
+ - `HOST_ACK`
306
+ - `SIGNATURE_PROMPTED`
307
+ - `TX_SUBMITTED`
308
+ - `TX_CONFIRMED`
309
+ - `TX_FINALIZED`
310
+ - include `txHash` when available on `TX_SUBMITTED` and `TX_CONFIRMED` if you have it
311
+
312
+ ### Required error statuses
313
+ - `SIGNATURE_DECLINED`
314
+ - `SIGNATURE_ERROR`
315
+ - `TX_REVERTED`
316
+ - `TX_FAILED` (supported)
317
+
318
+ ### Optional advanced statuses
319
+ - `TX_REPLACED`
320
+ - `TX_DROPPED`
321
+ - `SWAP_CROSSCHAIN_DESTINATION_CONFIRMED`
322
+
323
+ When `SIGNATURE_PROMPTED` is emitted, you typically call the wallet signer next.
324
+ Map wallet refusal codes/messages to:
325
+ - `SIGNATURE_DECLINED` for user cancellation (`4001`, `ACTION_REJECTED`).
326
+ - `SIGNATURE_ERROR` for other thrown errors before submission.
327
+
328
+ ### SDK default fallback (no `processBytecode`)
329
+
330
+ - If you run without a `processBytecode` prop, Deframe falls back to:
331
+ - `window.parent.postMessage({ type: 'REQUEST_SIGNATURE', clientTxId, bytecodes })`
332
+ - Keep this as a compatibility path only if your host is already wired to that message bridge.
333
+
334
+ ### Minimal host implementation
335
+
336
+ ```ts
337
+ export const processBytecode = async (
338
+ payload: {
339
+ clientTxId: string
340
+ bytecodes: Array<{ chainId?: number; to: string; data: string; value: string; gasLimit?: string }>
341
+ },
342
+ ctx: {
343
+ updateTxStatus: (event: any) => void
344
+ }
345
+ ) => {
346
+ const { clientTxId, bytecodes } = payload
347
+
348
+ try {
349
+ ctx.updateTxStatus({ type: 'HOST_ACK', clientTxId })
350
+
351
+ for (const tx of bytecodes) {
352
+ ctx.updateTxStatus({ type: 'SIGNATURE_PROMPTED', clientTxId })
353
+
354
+ // 1) sign + send transaction in your wallet stack
355
+ // 2) get tx hash
356
+ const txHash = await sendTransactionWithYourWallet(tx)
357
+
358
+ ctx.updateTxStatus({ type: 'TX_SUBMITTED', clientTxId, chainId: tx.chainId, txHash })
359
+
360
+ // Wait until mined/confirmed
361
+ await waitForConfirmation(txHash)
362
+ ctx.updateTxStatus({ type: 'TX_CONFIRMED', clientTxId, txHash })
363
+ }
364
+
365
+ ctx.updateTxStatus({ type: 'TX_FINALIZED', clientTxId })
366
+ } catch (error: any) {
367
+ const code = error?.code
368
+ const message = error?.message || 'Transaction failed'
369
+
370
+ if (code === 4001 || code === 'ACTION_REJECTED' || String(message).includes('rejected')) {
371
+ ctx.updateTxStatus({ type: 'SIGNATURE_DECLINED', clientTxId })
372
+ return
373
+ }
374
+
375
+ ctx.updateTxStatus({
376
+ type: 'SIGNATURE_ERROR',
377
+ clientTxId,
378
+ code: String(code || 'UNKNOWN_ERROR'),
379
+ message,
380
+ })
381
+ }
382
+ }
383
+ ```
384
+
385
+ ## Dynamic Integration (React)
386
+
387
+ ### Install
388
+
389
+ ```bash
390
+ pnpm add @dynamic-labs/sdk-react-core @dynamic-labs/ethereum viem
391
+ # or npm/yarn equivalents
392
+ ```
393
+
394
+ ### Provider setup
395
+
396
+ ```tsx
397
+ 'use client'
398
+
399
+ import { DynamicContextProvider } from '@dynamic-labs/sdk-react-core'
400
+ import { EthereumWalletConnectors } from '@dynamic-labs/ethereum'
401
+
402
+ export function DynamicProviders({ children }: { children: React.ReactNode }) {
403
+ return (
404
+ <DynamicContextProvider
405
+ settings={{
406
+ environmentId: process.env.NEXT_PUBLIC_DYNAMIC_ENV_ID!,
407
+ walletConnectors: [EthereumWalletConnectors],
408
+ }}
409
+ >
410
+ {children}
411
+ </DynamicContextProvider>
412
+ )
413
+ }
414
+ ```
415
+
416
+ ### `processBytecode` using Dynamic `primaryWallet`
417
+
418
+ ```tsx
419
+ 'use client'
420
+
421
+ import { useDynamicContext } from '@dynamic-labs/sdk-react-core'
422
+
423
+ type Bytecode = { chainId?: number; to: string; data: string; value: string }
424
+
425
+ export function useDynamicDeframeProcessBytecode() {
426
+ const { primaryWallet } = useDynamicContext()
427
+
428
+ return async (
429
+ payload: { clientTxId: string; bytecodes: Bytecode[] },
430
+ ctx: { updateTxStatus: (event: any) => void }
431
+ ) => {
432
+ const { clientTxId, bytecodes } = payload
433
+
434
+ if (!primaryWallet) {
435
+ ctx.updateTxStatus({
436
+ type: 'SIGNATURE_ERROR',
437
+ clientTxId,
438
+ code: 'NO_WALLET',
439
+ message: 'No connected Dynamic wallet',
440
+ })
441
+ return
442
+ }
443
+
444
+ try {
445
+ ctx.updateTxStatus({ type: 'HOST_ACK', clientTxId })
446
+
447
+ for (const tx of bytecodes) {
448
+ if (tx.chainId && primaryWallet.connector.supportsNetworkSwitching?.()) {
449
+ await primaryWallet.switchNetwork(tx.chainId)
450
+ }
451
+
452
+ ctx.updateTxStatus({ type: 'SIGNATURE_PROMPTED', clientTxId })
453
+
454
+ const walletClient = await primaryWallet.connector.getWalletClient()
455
+ const txHash = await walletClient.sendTransaction({
456
+ account: primaryWallet.address as `0x${string}`,
457
+ to: tx.to as `0x${string}`,
458
+ data: tx.data as `0x${string}`,
459
+ value: BigInt(tx.value || '0'),
460
+ })
461
+
462
+ ctx.updateTxStatus({
463
+ type: 'TX_SUBMITTED',
464
+ clientTxId,
465
+ chainId: tx.chainId,
466
+ txHash,
467
+ })
468
+
469
+ const publicClient = primaryWallet.connector.getPublicClient?.()
470
+ if (publicClient) {
471
+ await publicClient.waitForTransactionReceipt({ hash: txHash })
472
+ }
473
+
474
+ ctx.updateTxStatus({ type: 'TX_CONFIRMED', clientTxId, txHash })
475
+ }
476
+
477
+ ctx.updateTxStatus({ type: 'TX_FINALIZED', clientTxId })
478
+ } catch (error: any) {
479
+ if (error?.code === 4001 || error?.code === 'ACTION_REJECTED') {
480
+ ctx.updateTxStatus({ type: 'SIGNATURE_DECLINED', clientTxId })
481
+ return
482
+ }
483
+
484
+ ctx.updateTxStatus({
485
+ type: 'SIGNATURE_ERROR',
486
+ clientTxId,
487
+ code: String(error?.code || 'UNKNOWN_ERROR'),
488
+ message: String(error?.message || 'Dynamic transaction failed'),
489
+ })
490
+ }
491
+ }
492
+ }
493
+ ```
494
+
495
+ ## Privy Integration (React)
496
+
497
+ ### Install
498
+
499
+ ```bash
500
+ pnpm add @privy-io/react-auth viem
501
+ # or npm/yarn equivalents
502
+ ```
503
+
504
+ ### Provider setup
505
+
506
+ ```tsx
507
+ 'use client'
508
+
509
+ import { PrivyProvider } from '@privy-io/react-auth'
510
+
511
+ export function PrivyProviders({ children }: { children: React.ReactNode }) {
512
+ return (
513
+ <PrivyProvider
514
+ appId={process.env.NEXT_PUBLIC_PRIVY_APP_ID!}
515
+ clientId={process.env.NEXT_PUBLIC_PRIVY_CLIENT_ID!}
516
+ config={{
517
+ embeddedWallets: {
518
+ createOnLogin: 'users-without-wallets',
519
+ },
520
+ }}
521
+ >
522
+ {children}
523
+ </PrivyProvider>
524
+ )
525
+ }
526
+ ```
527
+
528
+ ### `processBytecode` using Privy connected wallets
529
+
530
+ ```tsx
531
+ 'use client'
532
+
533
+ import { useWallets } from '@privy-io/react-auth'
534
+
535
+ type Bytecode = { chainId?: number; to: string; data: string; value: string }
536
+
537
+ async function waitForReceipt(
538
+ provider: { request: (args: { method: string; params?: any[] }) => Promise<any> },
539
+ txHash: string
540
+ ) {
541
+ for (;;) {
542
+ const receipt = await provider.request({
543
+ method: 'eth_getTransactionReceipt',
544
+ params: [txHash],
545
+ })
546
+
547
+ if (receipt) return receipt
548
+ await new Promise((resolve) => setTimeout(resolve, 1500))
549
+ }
550
+ }
551
+
552
+ export function usePrivyDeframeProcessBytecode() {
553
+ const { wallets, ready } = useWallets()
554
+
555
+ return async (
556
+ payload: { clientTxId: string; bytecodes: Bytecode[] },
557
+ ctx: { updateTxStatus: (event: any) => void }
558
+ ) => {
559
+ const { clientTxId, bytecodes } = payload
560
+
561
+ if (!ready || wallets.length === 0) {
562
+ ctx.updateTxStatus({
563
+ type: 'SIGNATURE_ERROR',
564
+ clientTxId,
565
+ code: 'NO_WALLET',
566
+ message: 'No Privy wallet is connected',
567
+ })
568
+ return
569
+ }
570
+
571
+ const wallet = wallets[0]
572
+
573
+ try {
574
+ ctx.updateTxStatus({ type: 'HOST_ACK', clientTxId })
575
+
576
+ for (const tx of bytecodes) {
577
+ if (tx.chainId) {
578
+ await wallet.switchChain(tx.chainId)
579
+ }
580
+
581
+ const provider = await wallet.getEthereumProvider()
582
+
583
+ ctx.updateTxStatus({ type: 'SIGNATURE_PROMPTED', clientTxId })
584
+
585
+ const txHash = await provider.request({
586
+ method: 'eth_sendTransaction',
587
+ params: [
588
+ {
589
+ from: wallet.address,
590
+ to: tx.to,
591
+ data: tx.data,
592
+ value: `0x${BigInt(tx.value || '0').toString(16)}`,
593
+ },
594
+ ],
595
+ })
596
+
597
+ ctx.updateTxStatus({
598
+ type: 'TX_SUBMITTED',
599
+ clientTxId,
600
+ chainId: tx.chainId,
601
+ txHash,
602
+ })
603
+
604
+ await waitForReceipt(provider, txHash)
605
+ ctx.updateTxStatus({ type: 'TX_CONFIRMED', clientTxId, txHash })
606
+ }
607
+
608
+ ctx.updateTxStatus({ type: 'TX_FINALIZED', clientTxId })
609
+ } catch (error: any) {
610
+ if (error?.code === 4001 || error?.code === 'ACTION_REJECTED') {
611
+ ctx.updateTxStatus({ type: 'SIGNATURE_DECLINED', clientTxId })
612
+ return
613
+ }
614
+
615
+ ctx.updateTxStatus({
616
+ type: 'SIGNATURE_ERROR',
617
+ clientTxId,
618
+ code: String(error?.code || 'UNKNOWN_ERROR'),
619
+ message: String(error?.message || 'Privy transaction failed'),
620
+ })
621
+ }
622
+ }
623
+ }
624
+ ```
625
+
626
+ ## API Reference
627
+
628
+ ### `EarnWidget` props
629
+
630
+ ```ts
631
+ type EarnWidgetProps = {
632
+ className?: string
633
+ style?: React.CSSProperties
634
+ height?: string | number
635
+ enableScroll?: boolean
636
+ autoHeight?: boolean
637
+ onRouteChange?: (routeName: string) => void
638
+ }
639
+ ```
640
+
641
+ ### `SwapWidget` props
642
+
643
+ ```ts
644
+ type SwapWidgetProps = {
645
+ className?: string
646
+ style?: React.CSSProperties
647
+ height?: string | number
648
+ enableScroll?: boolean
649
+ autoHeight?: boolean
650
+ fromTokenAddress?: string
651
+ fromChainId?: number
652
+ toTokenAddress?: string
653
+ toChainId?: number
654
+ }
655
+ ```
656
+
657
+ ### `DeframeConfig`
658
+
659
+ ```ts
660
+ type DeframeConfig = {
661
+ DEFRAME_API_URL?: string
662
+ DEFRAME_API_KEY?: string
663
+ walletAddress?: string
664
+ userId?: string
665
+ strategiesLimit?: number
666
+ globalCurrency?: 'USD' | 'BRL'
667
+ globalCurrencyExchangeRate?: number
668
+ theme?: {
669
+ mode?: 'light' | 'dark' | 'auto'
670
+ preset?: 'default' | 'cryptocontrol'
671
+ overrides?: {
672
+ light?: { colors?: Record<string, string> }
673
+ dark?: { colors?: Record<string, string> }
674
+ }
675
+ }
676
+ debug?: boolean
677
+ components?: ComponentOverridesMap
678
+ behavior?: {
679
+ swap?: {
680
+ initialChainStrategy?: 'fixed' | 'wallet-balance'
681
+ openProcessingHistoryInline?: boolean
682
+ showHistoryTooltip?: boolean
683
+ directionButtonSpacing?: 'default' | 'compact'
684
+ }
685
+ actionSheets?: {
686
+ closeOnBackdropClick?: boolean
687
+ focusSearchOnOpen?: boolean
688
+ }
689
+ }
690
+ }
691
+ ```
692
+
693
+ ### Behavior Configuration
694
+
695
+ `config.behavior` lets host wallets opt into wallet-specific UI behavior without changing the SDK defaults for every consumer. Omit this config to keep the shared behavior.
696
+
697
+ ```tsx
698
+ const config = {
699
+ ...baseConfig,
700
+ behavior: {
701
+ swap: {
702
+ initialChainStrategy: 'wallet-balance',
703
+ openProcessingHistoryInline: true,
704
+ showHistoryTooltip: true,
705
+ directionButtonSpacing: 'compact',
706
+ },
707
+ actionSheets: {
708
+ closeOnBackdropClick: true,
709
+ focusSearchOnOpen: true,
710
+ },
711
+ },
712
+ }
713
+ ```
714
+
715
+ - `swap.initialChainStrategy`: defaults to `fixed`; use `wallet-balance` to start swap on the visible chain with the highest wallet balance.
716
+ - `swap.openProcessingHistoryInline`: defaults to `false`; set `true` to keep processing-screen history navigation inside the swap flow.
717
+ - `swap.showHistoryTooltip`: defaults to `false`; set `true` to expose the swap history icon label/tooltip.
718
+ - `swap.directionButtonSpacing`: defaults to `default`; use `compact` to reduce the vertical overlap around the simple swap direction button.
719
+ - `actionSheets.closeOnBackdropClick`: defaults to `false`; set `true` to close token/network selectors when the backdrop is clicked.
720
+ - `actionSheets.focusSearchOnOpen`: defaults to `false`; set `true` to focus selector search inputs when they open.
721
+
722
+ ## Component Overrides
723
+
724
+ Hosts can replace specific SDK view components via `config.components`, without forking. For example:
725
+
726
+ ```tsx
727
+ import { ChooseAnAssetSwapViewCardGrid } from 'deframe-sdk'
728
+
729
+ const config = {
730
+ ...baseConfig,
731
+ components: {
732
+ ChooseAnAssetSwapView: ChooseAnAssetSwapViewCardGrid
733
+ }
734
+ }
735
+ ```
736
+
737
+ If no override is set, the default component is used.
738
+
739
+ ## Troubleshooting
740
+
741
+ - Widget renders with no data:
742
+ - Verify `DEFRAME_API_URL`, `DEFRAME_API_KEY`, and `walletAddress`.
743
+ - Tx flow stuck in processing:
744
+ - Ensure host emits `TX_SUBMITTED`, then `TX_CONFIRMED`, then `TX_FINALIZED`.
745
+ - Signature rejected path not handled:
746
+ - Map wallet rejection errors (`4001` / `ACTION_REJECTED`) to `SIGNATURE_DECLINED`.
747
+ - Cross-route actions should be handled through `onRouteChange`.
748
+ - Widget appears with unexpected light cards/surfaces in dark mode:
749
+ - Inspect `.deframe-widget` computed variables and verify:
750
+ - `--color-bg-default`
751
+ - `--color-bg-raised`
752
+ - `--color-text-primary`
753
+ - If `--color-bg-raised` resolves to a light value while using dark theme, set widget-scoped fallbacks:
754
+ - `--color-bg-raised: var(--deframe-bg-raised, #232323)`
755
+ - `--color-brand-tint: #1e1e3f`
756
+ - Keep these overrides scoped to `.deframe-widget`, never global.
757
+
758
+ ## Machine Companion
759
+
760
+ For AI/editor ingestion, use [llms-full.txt](./llms-full.txt).