@orkid-labs/widget 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.
package/dist/index.js ADDED
@@ -0,0 +1,1042 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ OrkidSwapContext: () => OrkidSwapContext,
24
+ OrkidSwapIframe: () => OrkidSwapIframe,
25
+ OrkidSwapProvider: () => OrkidSwapProvider,
26
+ OrkidSwapWidget: () => OrkidSwapWidget,
27
+ defaultDarkTheme: () => defaultDarkTheme,
28
+ defaultLightTheme: () => defaultLightTheme,
29
+ mountOrkidSwap: () => mountOrkidSwap,
30
+ resolveTheme: () => resolveTheme,
31
+ themeToCssVariables: () => themeToCssVariables,
32
+ useOrkidSwapContext: () => useOrkidSwapContext
33
+ });
34
+ module.exports = __toCommonJS(index_exports);
35
+
36
+ // #style-inject:#style-inject
37
+ function styleInject(css, { insertAt } = {}) {
38
+ if (!css || typeof document === "undefined") return;
39
+ const head = document.head || document.getElementsByTagName("head")[0];
40
+ const style = document.createElement("style");
41
+ style.type = "text/css";
42
+ if (insertAt === "top") {
43
+ if (head.firstChild) {
44
+ head.insertBefore(style, head.firstChild);
45
+ } else {
46
+ head.appendChild(style);
47
+ }
48
+ } else {
49
+ head.appendChild(style);
50
+ }
51
+ if (style.styleSheet) {
52
+ style.styleSheet.cssText = css;
53
+ } else {
54
+ style.appendChild(document.createTextNode(css));
55
+ }
56
+ }
57
+
58
+ // src/styles.css
59
+ styleInject(".orkid-widget {\n font-family: var(--orkid-widget-font-family);\n color: var(--orkid-widget-text);\n background: var(--orkid-widget-bg);\n border-radius: var(--orkid-widget-radius);\n border: 1px solid var(--orkid-widget-border);\n padding: 1rem;\n width: 100%;\n max-width: 28rem;\n box-sizing: border-box;\n}\n.orkid-widget *,\n.orkid-widget *::before,\n.orkid-widget *::after {\n box-sizing: border-box;\n}\n.orkid-widget-card {\n background: var(--orkid-widget-card);\n color: var(--orkid-widget-card-foreground);\n border-radius: var(--orkid-widget-radius);\n border: 1px solid var(--orkid-widget-border);\n}\n.orkid-widget-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.75rem;\n margin-bottom: 1rem;\n}\n.orkid-widget-title {\n font-size: 1rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.orkid-widget-label {\n font-size: 0.875rem;\n color: var(--orkid-widget-muted-foreground);\n margin-bottom: 0.25rem;\n}\n.orkid-widget-row {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.orkid-widget-input,\n.orkid-widget-select-trigger,\n.orkid-widget-button {\n font-family: inherit;\n font-size: 0.875rem;\n border-radius: var(--orkid-widget-radius);\n border: 1px solid var(--orkid-widget-input);\n background: var(--orkid-widget-card);\n color: var(--orkid-widget-card-foreground);\n padding: 0.5rem 0.75rem;\n min-height: 2.5rem;\n}\n.orkid-widget-input {\n flex: 1;\n outline: none;\n}\n.orkid-widget-input:focus,\n.orkid-widget-select-trigger:focus,\n.orkid-widget-button:focus {\n outline: 2px solid var(--orkid-widget-ring);\n outline-offset: -1px;\n}\n.orkid-widget-button {\n cursor: pointer;\n background: var(--orkid-widget-primary);\n color: var(--orkid-widget-primary-foreground);\n border-color: var(--orkid-widget-primary);\n width: 100%;\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n}\n.orkid-widget-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.orkid-widget-button-secondary {\n background: var(--orkid-widget-muted);\n color: var(--orkid-widget-muted-foreground);\n border-color: var(--orkid-widget-border);\n}\n.orkid-widget-select-trigger {\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n cursor: pointer;\n min-width: 7rem;\n}\n.orkid-widget-dropdown {\n position: absolute;\n z-index: 50;\n top: 100%;\n left: 0;\n margin-top: 0.25rem;\n width: 18rem;\n background: var(--orkid-widget-popover);\n color: var(--orkid-widget-popover-foreground);\n border: 1px solid var(--orkid-widget-border);\n border-radius: var(--orkid-widget-radius);\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\n}\n.orkid-widget-dropdown-item {\n width: 100%;\n text-align: left;\n padding: 0.5rem 0.75rem;\n background: transparent;\n border: none;\n color: inherit;\n cursor: pointer;\n font-size: 0.875rem;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n.orkid-widget-dropdown-item:hover {\n background: var(--orkid-widget-accent);\n color: var(--orkid-widget-accent-foreground);\n}\n.orkid-widget-dropdown-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.orkid-widget-search {\n width: 100%;\n border: none;\n background: transparent;\n color: inherit;\n padding: 0.5rem 0.75rem;\n outline: none;\n}\n.orkid-widget-success {\n color: var(--orkid-widget-success);\n background: color-mix(in srgb, var(--orkid-widget-success) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--orkid-widget-success) 30%, transparent);\n border-radius: var(--orkid-widget-radius);\n padding: 0.75rem;\n font-size: 0.875rem;\n}\n.orkid-widget-error {\n color: var(--orkid-widget-danger);\n background: color-mix(in srgb, var(--orkid-widget-danger) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--orkid-widget-danger) 30%, transparent);\n border-radius: var(--orkid-widget-radius);\n padding: 0.75rem;\n font-size: 0.875rem;\n}\n.orkid-widget-warning {\n color: var(--orkid-widget-warning);\n background: color-mix(in srgb, var(--orkid-widget-warning) 10%, transparent);\n border: 1px solid color-mix(in srgb, var(--orkid-widget-warning) 30%, transparent);\n border-radius: var(--orkid-widget-radius);\n padding: 0.75rem;\n font-size: 0.875rem;\n}\n.orkid-widget-info {\n color: var(--orkid-widget-muted-foreground);\n background: color-mix(in srgb, var(--orkid-widget-primary) 5%, transparent);\n border: 1px solid color-mix(in srgb, var(--orkid-widget-primary) 20%, transparent);\n border-radius: var(--orkid-widget-radius);\n padding: 0.75rem;\n font-size: 0.75rem;\n}\n.orkid-widget-footer {\n font-size: 0.75rem;\n color: var(--orkid-widget-muted-foreground);\n text-align: center;\n margin-top: 0.75rem;\n}\n.orkid-widget-spin {\n animation: orkid-spin 1s linear infinite;\n}\n@keyframes orkid-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n");
60
+
61
+ // src/OrkidSwapProvider.tsx
62
+ var import_react2 = require("react");
63
+ var import_wagmi = require("wagmi");
64
+ var import_chains = require("wagmi/chains");
65
+ var import_connectors = require("wagmi/connectors");
66
+ var import_react_query = require("@tanstack/react-query");
67
+ var import_sdk = require("@orkid/sdk");
68
+
69
+ // src/context.tsx
70
+ var import_react = require("react");
71
+ var OrkidSwapContext = (0, import_react.createContext)(void 0);
72
+ function useOrkidSwapContext() {
73
+ const ctx = (0, import_react.useContext)(OrkidSwapContext);
74
+ if (!ctx) throw new Error("useOrkidSwapContext must be used within OrkidSwapProvider");
75
+ return ctx;
76
+ }
77
+
78
+ // src/theme.ts
79
+ var defaultLightTheme = {
80
+ background: "#ffffff",
81
+ card: "#ffffff",
82
+ cardForeground: "#0f172a",
83
+ primary: "#0052ff",
84
+ primaryForeground: "#ffffff",
85
+ text: "#0f172a",
86
+ muted: "#f1f5f9",
87
+ mutedForeground: "#64748b",
88
+ border: "#e2e8f0",
89
+ success: "#22c55e",
90
+ warning: "#f59e0b",
91
+ danger: "#ef4444",
92
+ radius: "0.625rem",
93
+ fontFamily: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
94
+ accent: "#f1f5f9",
95
+ accentForeground: "#0f172a",
96
+ popover: "#ffffff",
97
+ popoverForeground: "#0f172a",
98
+ input: "#e2e8f0",
99
+ ring: "#0052ff"
100
+ };
101
+ var defaultDarkTheme = {
102
+ background: "#0f172a",
103
+ card: "#1e293b",
104
+ cardForeground: "#f8fafc",
105
+ primary: "#3b82f6",
106
+ primaryForeground: "#ffffff",
107
+ text: "#f8fafc",
108
+ muted: "#334155",
109
+ mutedForeground: "#94a3b8",
110
+ border: "#334155",
111
+ success: "#4ade80",
112
+ warning: "#fbbf24",
113
+ danger: "#f87171",
114
+ radius: "0.625rem",
115
+ fontFamily: 'ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
116
+ accent: "#334155",
117
+ accentForeground: "#f8fafc",
118
+ popover: "#1e293b",
119
+ popoverForeground: "#f8fafc",
120
+ input: "#334155",
121
+ ring: "#3b82f6"
122
+ };
123
+ function resolveTheme(partial = {}) {
124
+ return { ...defaultLightTheme, ...partial };
125
+ }
126
+ function themeToCssVariables(theme) {
127
+ return {
128
+ "--orkid-widget-bg": theme.background,
129
+ "--orkid-widget-card": theme.card,
130
+ "--orkid-widget-card-foreground": theme.cardForeground,
131
+ "--orkid-widget-primary": theme.primary,
132
+ "--orkid-widget-primary-foreground": theme.primaryForeground,
133
+ "--orkid-widget-text": theme.text,
134
+ "--orkid-widget-muted": theme.muted,
135
+ "--orkid-widget-muted-foreground": theme.mutedForeground,
136
+ "--orkid-widget-border": theme.border,
137
+ "--orkid-widget-success": theme.success,
138
+ "--orkid-widget-warning": theme.warning,
139
+ "--orkid-widget-danger": theme.danger,
140
+ "--orkid-widget-radius": theme.radius,
141
+ "--orkid-widget-font-family": theme.fontFamily,
142
+ "--orkid-widget-accent": theme.accent,
143
+ "--orkid-widget-accent-foreground": theme.accentForeground,
144
+ "--orkid-widget-popover": theme.popover,
145
+ "--orkid-widget-popover-foreground": theme.popoverForeground,
146
+ "--orkid-widget-input": theme.input,
147
+ "--orkid-widget-ring": theme.ring
148
+ };
149
+ }
150
+
151
+ // src/OrkidSwapProvider.tsx
152
+ var import_jsx_runtime = require("react/jsx-runtime");
153
+ var DEFAULT_API_BASE_URL = "https://orkidlabs.xyz";
154
+ var queryClient = new import_react_query.QueryClient();
155
+ function OrkidSwapProvider({
156
+ apiKey = "",
157
+ apiBaseUrl = DEFAULT_API_BASE_URL,
158
+ partnerId,
159
+ walletMode = "built-in",
160
+ walletConnectProjectId,
161
+ wagmiConfig,
162
+ theme,
163
+ logoUrl,
164
+ brandName,
165
+ showPoweredBy = true,
166
+ supportedChains = [8453, 1, 42161, 137],
167
+ defaultFromToken,
168
+ defaultToToken,
169
+ defaultAmount,
170
+ defaultSlippageBps = 50,
171
+ tokenList,
172
+ gasless = true,
173
+ onQuote,
174
+ onSolve,
175
+ onError,
176
+ children
177
+ }) {
178
+ const client = (0, import_react2.useMemo)(
179
+ () => new import_sdk.OrkidClient({ apiKey, baseUrl: apiBaseUrl }),
180
+ [apiKey, apiBaseUrl]
181
+ );
182
+ const resolvedTheme = (0, import_react2.useMemo)(() => resolveTheme(theme), [theme]);
183
+ const resolvedWagmiConfig = (0, import_react2.useMemo)(() => {
184
+ if (walletMode === "external") return wagmiConfig;
185
+ if (walletMode !== "built-in") return void 0;
186
+ const chainsToUse = [import_chains.base];
187
+ if (supportedChains.includes(1)) chainsToUse.push(import_chains.mainnet);
188
+ if (supportedChains.includes(42161)) chainsToUse.push(import_chains.arbitrum);
189
+ if (supportedChains.includes(137)) chainsToUse.push(import_chains.polygon);
190
+ const connectors = [(0, import_connectors.injected)({ shimDisconnect: true })];
191
+ if (walletConnectProjectId) {
192
+ connectors.push(
193
+ (0, import_connectors.walletConnect)({
194
+ projectId: walletConnectProjectId,
195
+ metadata: {
196
+ name: brandName || "Orkid Swap",
197
+ description: "Gasless token swaps \u2014 competitive, no gas",
198
+ url: "https://orkidlabs.xyz",
199
+ icons: logoUrl ? [logoUrl] : []
200
+ }
201
+ })
202
+ );
203
+ }
204
+ return (0, import_wagmi.createConfig)({
205
+ chains: chainsToUse,
206
+ connectors,
207
+ transports: {
208
+ [import_chains.base.id]: (0, import_wagmi.http)("https://rpc.orkidlabs.com/rpc/base"),
209
+ [import_chains.mainnet.id]: (0, import_wagmi.http)("https://rpc.orkidlabs.com/rpc/ethereum"),
210
+ [import_chains.arbitrum.id]: (0, import_wagmi.http)("https://rpc.orkidlabs.com/rpc/arbitrum"),
211
+ [import_chains.polygon.id]: (0, import_wagmi.http)("https://rpc.orkidlabs.com/rpc/polygon")
212
+ }
213
+ });
214
+ }, [walletMode, wagmiConfig, supportedChains, walletConnectProjectId, brandName, logoUrl]);
215
+ const value = {
216
+ client,
217
+ wagmiConfig: resolvedWagmiConfig,
218
+ walletMode,
219
+ theme: resolvedTheme,
220
+ logoUrl,
221
+ brandName,
222
+ showPoweredBy,
223
+ supportedChains,
224
+ defaultFromToken,
225
+ defaultToToken,
226
+ defaultAmount,
227
+ defaultSlippageBps,
228
+ tokenList,
229
+ gasless,
230
+ partnerId,
231
+ onQuote,
232
+ onSolve,
233
+ onError
234
+ };
235
+ const content = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(OrkidSwapContext.Provider, { value, children });
236
+ if (walletMode === "built-in" && resolvedWagmiConfig) {
237
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_wagmi.WagmiProvider, { config: resolvedWagmiConfig, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient, children: content }) });
238
+ }
239
+ return content;
240
+ }
241
+
242
+ // src/OrkidSwapWidget.tsx
243
+ var import_react5 = require("react");
244
+ var import_wagmi2 = require("wagmi");
245
+ var import_viem = require("viem");
246
+ var import_sdk3 = require("@orkid/sdk");
247
+
248
+ // src/TokenSelect.tsx
249
+ var import_react3 = require("react");
250
+ var import_jsx_runtime2 = require("react/jsx-runtime");
251
+ function TokenSelect({
252
+ value,
253
+ onChange,
254
+ chainId,
255
+ chainName,
256
+ tokenList,
257
+ client,
258
+ label
259
+ }) {
260
+ const [open, setOpen] = (0, import_react3.useState)(false);
261
+ const [search, setSearch] = (0, import_react3.useState)("");
262
+ const [tokens, setTokens] = (0, import_react3.useState)(tokenList || []);
263
+ const [loading, setLoading] = (0, import_react3.useState)(false);
264
+ const ref = (0, import_react3.useRef)(null);
265
+ const searchRef = (0, import_react3.useRef)(null);
266
+ (0, import_react3.useEffect)(() => {
267
+ if (tokenList) {
268
+ setTokens(tokenList.filter((t2) => t2.chain === chainName));
269
+ return;
270
+ }
271
+ if (!open) return;
272
+ setLoading(true);
273
+ const t = setTimeout(async () => {
274
+ try {
275
+ const res = await client.listTokens({ search, limit: 50, chain: chainName });
276
+ if (res.ok && res.tokens) {
277
+ setTokens(res.tokens.filter((t2) => t2.address !== "0x0000000000000000000000000000000000000000"));
278
+ }
279
+ } catch (err) {
280
+ console.error("TokenSelect fetch failed:", err);
281
+ } finally {
282
+ setLoading(false);
283
+ }
284
+ }, 200);
285
+ return () => clearTimeout(t);
286
+ }, [open, search, chainName, tokenList, client]);
287
+ (0, import_react3.useEffect)(() => {
288
+ if (open && searchRef.current) searchRef.current.focus();
289
+ }, [open]);
290
+ (0, import_react3.useEffect)(() => {
291
+ const handler = (e) => {
292
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
293
+ };
294
+ if (open) document.addEventListener("mousedown", handler);
295
+ return () => document.removeEventListener("mousedown", handler);
296
+ }, [open]);
297
+ (0, import_react3.useEffect)(() => {
298
+ setSearch("");
299
+ if (!tokenList) setTokens([]);
300
+ }, [chainName, tokenList]);
301
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref, style: { position: "relative" }, children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
303
+ "button",
304
+ {
305
+ type: "button",
306
+ onClick: () => setOpen(!open),
307
+ className: "orkid-widget-select-trigger",
308
+ children: [
309
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: value ? value.symbol : "Select" }),
310
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "\u25BC" })
311
+ ]
312
+ }
313
+ ),
314
+ open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "orkid-widget-dropdown", children: [
315
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { borderBottom: "1px solid var(--orkid-widget-border)", padding: "0.5rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
316
+ "input",
317
+ {
318
+ ref: searchRef,
319
+ value: search,
320
+ onChange: (e) => setSearch(e.target.value),
321
+ placeholder: "Search token...",
322
+ className: "orkid-widget-search"
323
+ }
324
+ ) }),
325
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { maxHeight: "16rem", overflowY: "auto" }, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "0.75rem", textAlign: "center", color: "var(--orkid-widget-muted-foreground)" }, children: "Loading..." }) : tokens.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "0.75rem", textAlign: "center", color: "var(--orkid-widget-muted-foreground)" }, children: "No tokens found" }) : tokens.map((t) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
326
+ "button",
327
+ {
328
+ type: "button",
329
+ className: "orkid-widget-dropdown-item",
330
+ onClick: () => {
331
+ onChange(t);
332
+ setOpen(false);
333
+ setSearch("");
334
+ },
335
+ children: [
336
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontWeight: 500 }, children: t.symbol }),
337
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { fontSize: "0.75rem", fontFamily: "monospace", color: "var(--orkid-widget-muted-foreground)" }, children: [
338
+ t.address.slice(0, 6),
339
+ "...",
340
+ t.address.slice(-4)
341
+ ] })
342
+ ]
343
+ },
344
+ t.address
345
+ )) })
346
+ ] })
347
+ ] });
348
+ }
349
+
350
+ // src/ChainSelect.tsx
351
+ var import_react4 = require("react");
352
+ var import_sdk2 = require("@orkid/sdk");
353
+ var import_jsx_runtime3 = require("react/jsx-runtime");
354
+ var CHAIN_NAME = {
355
+ 8453: "base",
356
+ 1: "ethereum",
357
+ 42161: "arbitrum",
358
+ 137: "polygon"
359
+ };
360
+ var CHAIN_LIVE = {
361
+ 8453: true,
362
+ 1: true,
363
+ 42161: true,
364
+ 137: true
365
+ };
366
+ function ChainSelect({
367
+ selected,
368
+ onSelect,
369
+ supported
370
+ }) {
371
+ const [open, setOpen] = (0, import_react4.useState)(false);
372
+ const ref = (0, import_react4.useRef)(null);
373
+ (0, import_react4.useEffect)(() => {
374
+ const handler = (e) => {
375
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
376
+ };
377
+ if (open) document.addEventListener("mousedown", handler);
378
+ return () => document.removeEventListener("mousedown", handler);
379
+ }, [open]);
380
+ const currentConfig = import_sdk2.ORKID_CHAIN_CONFIG[selected];
381
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref, style: { position: "relative" }, children: [
382
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
383
+ "button",
384
+ {
385
+ type: "button",
386
+ onClick: () => setOpen(!open),
387
+ className: "orkid-widget-select-trigger",
388
+ style: { display: "flex", alignItems: "center", gap: "0.5rem" },
389
+ children: [
390
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
391
+ "span",
392
+ {
393
+ style: {
394
+ width: "0.5rem",
395
+ height: "0.5rem",
396
+ borderRadius: "50%",
397
+ background: currentConfig?.color || "var(--orkid-widget-primary)"
398
+ }
399
+ }
400
+ ),
401
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: currentConfig?.shortName || "BASE" }),
402
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "\u25BC" })
403
+ ]
404
+ }
405
+ ),
406
+ open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "orkid-widget-dropdown", style: { right: 0, left: "auto", width: "12rem" }, children: supported.map((id) => {
407
+ const config = import_sdk2.ORKID_CHAIN_CONFIG[id];
408
+ const live = CHAIN_LIVE[id];
409
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
410
+ "button",
411
+ {
412
+ type: "button",
413
+ className: "orkid-widget-dropdown-item",
414
+ onClick: () => {
415
+ if (live) onSelect(id);
416
+ setOpen(false);
417
+ },
418
+ disabled: !live,
419
+ title: live ? void 0 : "Contact Orkid to enable this chain",
420
+ children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "orkid-widget-row", style: { gap: "0.5rem" }, children: [
422
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
423
+ "span",
424
+ {
425
+ style: {
426
+ width: "0.5rem",
427
+ height: "0.5rem",
428
+ borderRadius: "50%",
429
+ background: config?.color || "var(--orkid-widget-primary)"
430
+ }
431
+ }
432
+ ),
433
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: config?.name || CHAIN_NAME[id] })
434
+ ] }),
435
+ id === selected && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "var(--orkid-widget-primary)" }, children: "\u2713" }),
436
+ !live && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: "0.7rem", color: "var(--orkid-widget-muted-foreground)" }, children: "soon" })
437
+ ]
438
+ },
439
+ id
440
+ );
441
+ }) })
442
+ ] });
443
+ }
444
+
445
+ // src/OrkidSwapWidget.tsx
446
+ var import_jsx_runtime4 = require("react/jsx-runtime");
447
+ var erc20Abi = (0, import_viem.parseAbi)([
448
+ "function allowance(address owner, address spender) view returns (uint256)",
449
+ "function approve(address spender, uint256 amount) returns (bool)",
450
+ "function balanceOf(address account) view returns (uint256)"
451
+ ]);
452
+ var permit2Abi = (0, import_viem.parseAbi)([
453
+ "function nonceBitmap(address owner, uint256 wordPos) view returns (uint256)"
454
+ ]);
455
+ var PERMIT_TRANSFER_FROM_TYPES = {
456
+ PermitTransferFrom: [
457
+ { name: "permitted", type: "TokenPermissions" },
458
+ { name: "spender", type: "address" },
459
+ { name: "nonce", type: "uint256" },
460
+ { name: "deadline", type: "uint256" }
461
+ ],
462
+ TokenPermissions: [
463
+ { name: "token", type: "address" },
464
+ { name: "amount", type: "uint256" }
465
+ ]
466
+ };
467
+ var CHAIN_NAME2 = {
468
+ 8453: "base",
469
+ 1: "ethereum",
470
+ 42161: "arbitrum",
471
+ 137: "polygon"
472
+ };
473
+ var CHAIN_LIVE2 = {
474
+ 8453: true,
475
+ 1: true,
476
+ 42161: true,
477
+ 137: true
478
+ };
479
+ function OrkidSwapWidget({ className }) {
480
+ const ctx = useOrkidSwapContext();
481
+ const client = ctx.client;
482
+ const [selectedChainId, setSelectedChainId] = (0, import_react5.useState)(ctx.supportedChains[0] ?? 8453);
483
+ const [fromToken, setFromToken] = (0, import_react5.useState)(ctx.defaultFromToken);
484
+ const [toToken, setToToken] = (0, import_react5.useState)(ctx.defaultToToken);
485
+ const [amount, setAmount] = (0, import_react5.useState)(ctx.defaultAmount ?? "");
486
+ const [slippageBps, setSlippageBps] = (0, import_react5.useState)(ctx.defaultSlippageBps);
487
+ const [showSlippage, setShowSlippage] = (0, import_react5.useState)(false);
488
+ const [quote, setQuote] = (0, import_react5.useState)(null);
489
+ const [loading, setLoading] = (0, import_react5.useState)(null);
490
+ const [error, setError] = (0, import_react5.useState)(null);
491
+ const [txHash, setTxHash] = (0, import_react5.useState)(null);
492
+ const [execMode, setExecMode] = (0, import_react5.useState)(null);
493
+ const { address, isConnected } = (0, import_wagmi2.useAccount)();
494
+ const walletChainId = (0, import_wagmi2.useChainId)();
495
+ const { connect, connectors, isPending: isConnecting } = (0, import_wagmi2.useConnect)();
496
+ const { disconnect } = (0, import_wagmi2.useDisconnect)();
497
+ const { switchChain } = (0, import_wagmi2.useSwitchChain)();
498
+ const publicClient = (0, import_wagmi2.usePublicClient)({ chainId: selectedChainId });
499
+ const { signTypedDataAsync } = (0, import_wagmi2.useSignTypedData)();
500
+ const { writeContract: approveWrite, data: approveTxHash, isPending: isApproving } = (0, import_wagmi2.useWriteContract)();
501
+ const { isSuccess: approvalConfirmed } = (0, import_wagmi2.useWaitForTransactionReceipt)({ hash: approveTxHash });
502
+ const { sendTransactionAsync, data: fallbackTxHash, isPending: isSendingFallback } = (0, import_wagmi2.useSendTransaction)();
503
+ const { isSuccess: fallbackConfirmed } = (0, import_wagmi2.useWaitForTransactionReceipt)({ hash: fallbackTxHash });
504
+ const { isSuccess: swapConfirmed } = (0, import_wagmi2.useWaitForTransactionReceipt)({
505
+ hash: txHash,
506
+ chainId: selectedChainId
507
+ });
508
+ const isOnCorrectChain = walletChainId === selectedChainId;
509
+ const chainName = CHAIN_NAME2[selectedChainId] ?? "base";
510
+ const chainLive = CHAIN_LIVE2[selectedChainId] ?? false;
511
+ const { data: fromTokenBalance } = (0, import_wagmi2.useReadContract)({
512
+ address: fromToken?.address,
513
+ abi: erc20Abi,
514
+ functionName: "balanceOf",
515
+ args: address && fromToken ? [address] : void 0,
516
+ chainId: selectedChainId,
517
+ query: { enabled: !!address && !!fromToken && chainLive }
518
+ });
519
+ const { data: erc20Allowance, refetch: refetchAllowance } = (0, import_wagmi2.useReadContract)({
520
+ address: fromToken?.address,
521
+ abi: erc20Abi,
522
+ functionName: "allowance",
523
+ args: address && fromToken ? [address, import_sdk3.PERMIT2] : void 0,
524
+ chainId: selectedChainId,
525
+ query: { enabled: !!address && !!fromToken && chainLive }
526
+ });
527
+ (0, import_react5.useEffect)(() => {
528
+ if (approvalConfirmed) {
529
+ refetchAllowance();
530
+ setLoading(null);
531
+ }
532
+ }, [approvalConfirmed, refetchAllowance]);
533
+ (0, import_react5.useEffect)(() => {
534
+ if (fallbackConfirmed && fallbackTxHash) {
535
+ setTxHash(fallbackTxHash);
536
+ setLoading(null);
537
+ setAmount("");
538
+ setQuote(null);
539
+ client.confirmTransaction?.(fallbackTxHash, chainName).catch(() => {
540
+ });
541
+ ctx.onSolve?.({ ok: true, transaction: { txHash: fallbackTxHash, to: "", data: "", value: "0", chain: chainName }, computeMs: 0 });
542
+ }
543
+ }, [fallbackConfirmed, fallbackTxHash, chainName, ctx, client]);
544
+ const chainConfig = (0, import_react5.useMemo)(() => {
545
+ try {
546
+ return (0, import_sdk3.chainConfigFromName)(chainName);
547
+ } catch {
548
+ return void 0;
549
+ }
550
+ }, [chainName]);
551
+ const fetchQuote = (0, import_react5.useCallback)(async () => {
552
+ if (!amount || Number.parseFloat(amount) <= 0 || !fromToken || !toToken || !chainLive) {
553
+ setQuote(null);
554
+ return;
555
+ }
556
+ setLoading("quote");
557
+ setError(null);
558
+ try {
559
+ const res = await client.getQuote({
560
+ from: fromToken.symbol,
561
+ to: toToken.symbol,
562
+ amount,
563
+ chain: chainName,
564
+ fromAddress: fromToken.address,
565
+ toAddress: toToken.address,
566
+ fromDecimals: fromToken.decimals,
567
+ toDecimals: toToken.decimals
568
+ });
569
+ setQuote(res);
570
+ ctx.onQuote?.(res);
571
+ if (!res.ok) setError(res.error || "Quote failed");
572
+ } catch (e) {
573
+ setError(e.message || "Quote failed");
574
+ setQuote(null);
575
+ ctx.onError?.(e.message || "Quote failed");
576
+ } finally {
577
+ setLoading(null);
578
+ }
579
+ }, [amount, fromToken, toToken, chainName, chainLive, client, ctx]);
580
+ (0, import_react5.useEffect)(() => {
581
+ const t = setTimeout(fetchQuote, 400);
582
+ return () => clearTimeout(t);
583
+ }, [fetchQuote]);
584
+ (0, import_react5.useEffect)(() => {
585
+ setFromToken(ctx.defaultFromToken);
586
+ setToToken(ctx.defaultToToken);
587
+ setAmount(ctx.defaultAmount ?? "");
588
+ setQuote(null);
589
+ setError(null);
590
+ setTxHash(null);
591
+ }, [selectedChainId, ctx.defaultFromToken, ctx.defaultToToken, ctx.defaultAmount]);
592
+ async function findUnusedNonce(owner) {
593
+ if (!publicClient) throw new Error("No public client");
594
+ const arr = new Uint32Array(1);
595
+ crypto.getRandomValues(arr);
596
+ const startWord = BigInt(arr[0] >> 8);
597
+ const MAX_OFFSET = BigInt(1e3);
598
+ const MODULUS = BigInt(1e6);
599
+ const EIGHT = BigInt(8);
600
+ const ONE = BigInt(1);
601
+ const ZERO = BigInt(0);
602
+ for (let offset = BigInt(0); offset < MAX_OFFSET; offset++) {
603
+ const wordPos = (startWord + offset) % MODULUS;
604
+ const bitmap = await publicClient.readContract({
605
+ address: import_sdk3.PERMIT2,
606
+ abi: permit2Abi,
607
+ functionName: "nonceBitmap",
608
+ args: [owner, wordPos]
609
+ });
610
+ if (bitmap === import_viem.maxUint256) continue;
611
+ for (let bitPos = 0; bitPos < 256; bitPos++) {
612
+ const bit = ONE << BigInt(bitPos);
613
+ if ((bitmap & bit) === ZERO) {
614
+ return wordPos << EIGHT | BigInt(bitPos);
615
+ }
616
+ }
617
+ }
618
+ throw new Error("No unused Permit2 nonce found");
619
+ }
620
+ function parseAmount(value, decimals) {
621
+ const normalized = value.trim();
622
+ if (!/^\d+(\.\d+)?$/.test(normalized)) throw new Error("Invalid amount");
623
+ const [whole, fraction = ""] = normalized.split(".");
624
+ if (fraction.length > decimals) throw new Error(`Amount supports at most ${decimals} decimals`);
625
+ const scale = BigInt("1" + "0".repeat(decimals));
626
+ return BigInt(whole) * scale + BigInt(fraction.padEnd(decimals, "0") || "0");
627
+ }
628
+ async function handleSwap() {
629
+ if (!isConnected || !address || !fromToken || !toToken || !quote?.ok) {
630
+ setError("Connect a wallet and get a valid quote");
631
+ return;
632
+ }
633
+ if (!isOnCorrectChain || !chainLive) {
634
+ setError(`Please switch to ${chainConfig?.shortName || "Base"}`);
635
+ return;
636
+ }
637
+ setError(null);
638
+ setTxHash(null);
639
+ try {
640
+ const amountRaw = parseAmount(amount, fromToken.decimals);
641
+ if (fromTokenBalance !== void 0 && fromTokenBalance < amountRaw) {
642
+ const balHuman = Number(fromTokenBalance) / 10 ** fromToken.decimals;
643
+ setError(`Insufficient ${fromToken.symbol} balance. You have ${balHuman.toFixed(6)} ${fromToken.symbol} but tried ${amount}.`);
644
+ return;
645
+ }
646
+ const needsApproval = erc20Allowance === void 0 || erc20Allowance === BigInt(0);
647
+ if (needsApproval) {
648
+ setLoading("approve");
649
+ approveWrite({
650
+ address: fromToken.address,
651
+ abi: erc20Abi,
652
+ functionName: "approve",
653
+ args: [import_sdk3.PERMIT2, import_viem.maxUint256],
654
+ chainId: selectedChainId
655
+ });
656
+ return;
657
+ }
658
+ const nonce = await findUnusedNonce(address);
659
+ const deadline = BigInt(Math.floor(Date.now() / 1e3) + 3600);
660
+ const spender = chainConfig?.tvmExecutor;
661
+ if (!spender) throw new Error("No TVMExecutor configured for this chain");
662
+ setLoading("sign");
663
+ const signature = await signTypedDataAsync({
664
+ domain: (0, import_sdk3.buildPermit2Domain)(Number(walletChainId)),
665
+ types: PERMIT_TRANSFER_FROM_TYPES,
666
+ primaryType: "PermitTransferFrom",
667
+ message: {
668
+ permitted: { token: fromToken.address, amount: amountRaw },
669
+ spender,
670
+ nonce,
671
+ deadline
672
+ }
673
+ });
674
+ if (!signature || signature.length < 10) {
675
+ setError("Signature not provided");
676
+ setLoading(null);
677
+ return;
678
+ }
679
+ const belowMin = quote?.gaslessEligible === false;
680
+ const wantsGasless = ctx.gasless && !belowMin;
681
+ setLoading("solve");
682
+ setExecMode(wantsGasless ? "gasless" : "user-pays");
683
+ const permit = {
684
+ permitted: { token: fromToken.address, amount: amountRaw.toString() },
685
+ nonce: nonce.toString(),
686
+ deadline: deadline.toString()
687
+ };
688
+ const solveRes = await client.solve({
689
+ from: fromToken.symbol,
690
+ to: toToken.symbol,
691
+ amount,
692
+ chain: chainName,
693
+ user: address,
694
+ fromAddress: fromToken.address,
695
+ toAddress: toToken.address,
696
+ fromDecimals: fromToken.decimals,
697
+ toDecimals: toToken.decimals,
698
+ permit,
699
+ signature,
700
+ slippageBps,
701
+ dryRun: !wantsGasless
702
+ });
703
+ if (solveRes.ok && solveRes.transaction?.txHash) {
704
+ setTxHash(solveRes.transaction.txHash);
705
+ setAmount("");
706
+ setQuote(null);
707
+ ctx.onSolve?.(solveRes);
708
+ return;
709
+ }
710
+ if (solveRes.error?.includes("Gas estimation failed")) {
711
+ setError(`Solver rejected the swap: ${solveRes.error}`);
712
+ setLoading(null);
713
+ return;
714
+ }
715
+ if (!wantsGasless) {
716
+ if (!solveRes.ok || !solveRes.transaction) {
717
+ setError(solveRes.error || "Failed to encode swap");
718
+ setLoading(null);
719
+ return;
720
+ }
721
+ setExecMode("user-pays");
722
+ await sendTransactionAsync({
723
+ to: solveRes.transaction.to,
724
+ data: solveRes.transaction.data,
725
+ value: BigInt(solveRes.transaction.value || "0"),
726
+ chainId: selectedChainId
727
+ });
728
+ return;
729
+ }
730
+ const dryRes = await client.dryRun({
731
+ from: fromToken.symbol,
732
+ to: toToken.symbol,
733
+ amount,
734
+ chain: chainName,
735
+ user: address,
736
+ fromAddress: fromToken.address,
737
+ toAddress: toToken.address,
738
+ fromDecimals: fromToken.decimals,
739
+ toDecimals: toToken.decimals,
740
+ permit,
741
+ signature,
742
+ slippageBps
743
+ });
744
+ if (!dryRes.ok || !dryRes.transaction) {
745
+ setError(dryRes.error || solveRes.error || "Solver failed to encode swap");
746
+ setLoading(null);
747
+ return;
748
+ }
749
+ setExecMode("user-pays");
750
+ await sendTransactionAsync({
751
+ to: dryRes.transaction.to,
752
+ data: dryRes.transaction.data,
753
+ value: BigInt(dryRes.transaction.value || "0"),
754
+ chainId: selectedChainId
755
+ });
756
+ } catch (e) {
757
+ if (e.code === 4001 || e.message?.includes("rejected")) {
758
+ setError("Signature or transaction rejected");
759
+ } else {
760
+ setError(`[${e.code || "?"}] ${e.message || "Swap failed"}`);
761
+ }
762
+ setLoading(null);
763
+ ctx.onError?.(e.message || "Swap failed");
764
+ }
765
+ }
766
+ function handleConnect() {
767
+ const connector = connectors[0];
768
+ if (connector) {
769
+ connect({ connector });
770
+ } else {
771
+ setError("No wallet connector found");
772
+ }
773
+ }
774
+ function handleChainChange(id) {
775
+ if (!CHAIN_LIVE2[id]) return;
776
+ setSelectedChainId(id);
777
+ switchChain({ chainId: id });
778
+ }
779
+ const isBusy = loading !== null || isConnecting || isApproving || isSendingFallback;
780
+ const highImpact = quote?.ok && quote.quote?.priceImpactBps != null && quote.quote.priceImpactBps >= 300;
781
+ const canSwap = isConnected && isOnCorrectChain && chainLive && !!amount && !!fromToken && !!toToken && quote?.ok && !isBusy && !highImpact;
782
+ const buttonLabel = () => {
783
+ if (!isConnected) return "Connect Wallet";
784
+ if (!isOnCorrectChain || !chainLive) return `Switch to ${chainConfig?.shortName || "Base"}`;
785
+ if (loading === "quote") return "Fetching quote...";
786
+ if (loading === "approve" || isApproving) return "Approve Permit2...";
787
+ if (loading === "sign") return "Sign in wallet...";
788
+ if (loading === "solve" && execMode === "gasless") return "Executing gasless swap...";
789
+ if (loading === "solve" && execMode === "user-pays") return "Preparing fallback...";
790
+ if (isSendingFallback) return "Confirm in wallet...";
791
+ return "Swap";
792
+ };
793
+ const handleButtonClick = () => {
794
+ if (!isConnected) return handleConnect();
795
+ if (!isOnCorrectChain || !chainLive) {
796
+ if (chainLive) switchChain({ chainId: selectedChainId });
797
+ return;
798
+ }
799
+ handleSwap();
800
+ };
801
+ const explorer = chainConfig?.explorer || "https://basescan.org";
802
+ const style = (0, import_react5.useMemo)(() => themeToCssVariables(ctx.theme), [ctx.theme]);
803
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `orkid-widget ${className ?? ""}`, style, children: [
804
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-header", children: [
805
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-title", children: [
806
+ ctx.logoUrl && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { src: ctx.logoUrl, alt: "", className: "w-6 h-6 object-contain" }),
807
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: ctx.brandName || "Swap" })
808
+ ] }),
809
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChainSelect, { selected: selectedChainId, onSelect: handleChainChange, supported: ctx.supportedChains })
810
+ ] }),
811
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "space-y-4", children: [
812
+ isConnected && address ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between" }, children: [
813
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "orkid-widget-muted-text", style: { fontFamily: "monospace", fontSize: "0.875rem" }, children: [
814
+ address.slice(0, 6),
815
+ "...",
816
+ address.slice(-4)
817
+ ] }),
818
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "orkid-widget-button-secondary", style: { width: "auto" }, onClick: () => disconnect(), children: "Disconnect" })
819
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "orkid-widget-button", onClick: handleConnect, disabled: isConnecting, children: isConnecting ? "Connecting..." : "Connect Wallet" }),
820
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
821
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orkid-widget-label", children: "From" }),
822
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", children: [
823
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TokenSelect, { value: fromToken, onChange: setFromToken, chainId: selectedChainId, chainName, tokenList: ctx.tokenList, client }),
824
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
825
+ "input",
826
+ {
827
+ type: "number",
828
+ value: amount,
829
+ onChange: (e) => setAmount(e.target.value),
830
+ placeholder: "0.0",
831
+ className: "orkid-widget-input",
832
+ disabled: !chainLive
833
+ }
834
+ )
835
+ ] })
836
+ ] }),
837
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
838
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orkid-widget-label", children: "To" }),
839
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", children: [
840
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TokenSelect, { value: toToken, onChange: setToToken, chainId: selectedChainId, chainName, tokenList: ctx.tokenList, client }),
841
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orkid-widget-input", style: { display: "flex", alignItems: "center", fontFamily: "monospace", fontSize: "0.875rem" }, children: loading === "quote" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "orkid-widget-spin", children: "\u21BB" }) : quote?.ok ? quote.quote?.amountOut || "--" : "--" })
842
+ ] })
843
+ ] }),
844
+ quote?.ok && quote.savings && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-card", style: { padding: "0.75rem" }, children: [
845
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between", fontSize: "0.875rem" }, children: [
846
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--orkid-widget-muted-foreground)" }, children: "Orkid Fee" }),
847
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { color: "var(--orkid-widget-primary)", fontWeight: 600 }, children: [
848
+ quote.savings.orkidBps,
849
+ " bps"
850
+ ] })
851
+ ] }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between", fontSize: "0.875rem" }, children: [
853
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--orkid-widget-muted-foreground)" }, children: "MetaMask Avg" }),
854
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { textDecoration: "line-through" }, children: [
855
+ quote.savings.metamaskBps,
856
+ " bps"
857
+ ] })
858
+ ] }),
859
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between", fontSize: "0.875rem", borderTop: "1px solid var(--orkid-widget-border)", paddingTop: "0.5rem", marginTop: "0.5rem" }, children: [
860
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--orkid-widget-primary)" }, children: "You Save" }),
861
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { fontWeight: 700, color: "var(--orkid-widget-primary)" }, children: [
862
+ quote.savings.savingsMultiplier,
863
+ " lower fees"
864
+ ] })
865
+ ] }),
866
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between", fontSize: "0.75rem" }, children: [
867
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--orkid-widget-muted-foreground)" }, children: "Gas" }),
868
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--orkid-widget-success)" }, children: quote?.gaslessEligible === false ? "You pay (below $20 gasless min)" : execMode === "user-pays" ? "User pays" : "Gasless" })
869
+ ] })
870
+ ] }),
871
+ quote?.ok && quote.quote?.amountOut && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
872
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between", fontSize: "0.875rem" }, children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--orkid-widget-muted-foreground)" }, children: "Minimum receive" }),
874
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { fontFamily: "monospace" }, children: [
875
+ (Number(quote.quote.amountOut) * (1 - slippageBps / 1e4)).toFixed(6),
876
+ " ",
877
+ toToken?.symbol
878
+ ] })
879
+ ] }),
880
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", style: { justifyContent: "space-between", fontSize: "0.75rem" }, children: [
881
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { onClick: () => setShowSlippage(!showSlippage), style: { color: "var(--orkid-widget-muted-foreground)", background: "none", border: "none", cursor: "pointer" }, children: [
882
+ "Slippage: ",
883
+ (slippageBps / 100).toFixed(1),
884
+ "% ",
885
+ showSlippage ? "\u25B2" : "\u25BC"
886
+ ] }),
887
+ showSlippage && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-row", children: [
888
+ [10, 50, 100, 200].map((bps) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
889
+ "button",
890
+ {
891
+ onClick: () => setSlippageBps(bps),
892
+ className: slippageBps === bps ? "orkid-widget-button" : "orkid-widget-button-secondary",
893
+ style: { width: "auto", padding: "0.25rem 0.5rem", fontSize: "0.75rem" },
894
+ children: [
895
+ bps / 100,
896
+ "%"
897
+ ]
898
+ },
899
+ bps
900
+ )),
901
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
902
+ "input",
903
+ {
904
+ type: "number",
905
+ min: 1,
906
+ max: 500,
907
+ step: 1,
908
+ placeholder: "custom bps",
909
+ className: "orkid-widget-input",
910
+ style: { width: "6.5rem", padding: "0.25rem 0.5rem", fontSize: "0.75rem" },
911
+ onChange: (e) => {
912
+ const v = Number(e.target.value);
913
+ if (v > 0 && v <= 500) setSlippageBps(v);
914
+ }
915
+ }
916
+ )
917
+ ] })
918
+ ] })
919
+ ] }),
920
+ quote?.ok && quote.quote?.priceImpactBps != null && quote.quote.priceImpactBps > 100 && (quote.quote.priceImpactBps >= 300 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-warning", children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontWeight: 600 }, children: [
922
+ "High Price Impact: ",
923
+ (quote.quote.priceImpactBps / 100).toFixed(1),
924
+ "%"
925
+ ] }),
926
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontSize: "0.875rem", margin: "0.25rem 0 0" }, children: "This size exceeds available pool liquidity. Contact Orkid for OTC/API access." })
927
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { color: "var(--orkid-widget-warning)", fontSize: "0.75rem" }, children: [
928
+ "Price impact: ",
929
+ (quote.quote.priceImpactBps / 100).toFixed(2),
930
+ "%"
931
+ ] })),
932
+ txHash && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-success", children: [
933
+ swapConfirmed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
934
+ "Swap confirmed",
935
+ execMode === "user-pays" ? " (you paid gas)" : " (gasless)"
936
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
937
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "orkid-widget-spin", style: { marginRight: "0.5rem" }, children: "\u21BB" }),
938
+ "Swap submitted",
939
+ execMode === "user-pays" ? " (you paid gas)" : " (gasless)",
940
+ " \u2014 confirming\u2026"
941
+ ] }),
942
+ " ",
943
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: `${explorer}/tx/${txHash}`, target: "_blank", rel: "noopener noreferrer", style: { textDecoration: "underline" }, children: "View" }),
944
+ swapConfirmed && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
945
+ "button",
946
+ {
947
+ className: "orkid-widget-button-secondary",
948
+ style: { width: "auto", padding: "0.25rem 0.75rem", fontSize: "0.75rem", marginLeft: "0.5rem" },
949
+ onClick: () => {
950
+ setTxHash(null);
951
+ setExecMode(null);
952
+ setQuote(null);
953
+ setAmount("");
954
+ },
955
+ children: "Swap again"
956
+ }
957
+ )
958
+ ] }),
959
+ quote?.ok && quote.gaslessEligible === false && !txHash && !error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "var(--orkid-widget-muted-foreground)", fontSize: "0.75rem" }, children: "Below the gasless minimum \u2014 you will submit this swap and pay gas yourself." }),
960
+ isConnected && canSwap && !txHash && !error && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "orkid-widget-info", children: [
961
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontWeight: 600 }, children: "How this works:" }),
962
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "1. Sign a permit off-chain (no gas) to authorize the solver." }),
963
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "2. The solver sends the transaction and pays the gas." })
964
+ ] }),
965
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: "orkid-widget-button", onClick: handleButtonClick, disabled: isConnected && !canSwap, children: [
966
+ isBusy && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "orkid-widget-spin", style: { marginRight: "0.5rem" }, children: "\u21BB" }),
967
+ buttonLabel()
968
+ ] }),
969
+ error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orkid-widget-error", children: error }),
970
+ ctx.showPoweredBy && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "orkid-widget-footer", children: "Powered by Orkid \xB7 Competitive fee \xB7 Gasless" })
971
+ ] })
972
+ ] });
973
+ }
974
+
975
+ // src/IframeWidget.tsx
976
+ var import_react6 = require("react");
977
+ var import_jsx_runtime5 = require("react/jsx-runtime");
978
+ function OrkidSwapIframe({
979
+ src = "https://widget.orkidlabs.xyz",
980
+ partner,
981
+ brandName,
982
+ logoUrl,
983
+ theme,
984
+ fromToken,
985
+ toToken,
986
+ amount,
987
+ showPoweredBy,
988
+ allowFullScreen,
989
+ className,
990
+ style
991
+ }) {
992
+ const url = (0, import_react6.useMemo)(() => {
993
+ const u = new URL(src);
994
+ if (partner) u.searchParams.set("partner", partner);
995
+ if (brandName) u.searchParams.set("brand", brandName);
996
+ if (logoUrl) u.searchParams.set("logo", logoUrl);
997
+ if (theme) u.searchParams.set("theme", encodeURIComponent(JSON.stringify(theme)));
998
+ if (fromToken) u.searchParams.set("from", fromToken);
999
+ if (toToken) u.searchParams.set("to", toToken);
1000
+ if (amount) u.searchParams.set("amount", amount);
1001
+ if (showPoweredBy !== void 0) u.searchParams.set("poweredBy", String(showPoweredBy));
1002
+ return u.toString();
1003
+ }, [src, partner, brandName, logoUrl, theme, fromToken, toToken, amount, showPoweredBy]);
1004
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1005
+ "iframe",
1006
+ {
1007
+ src: url,
1008
+ className,
1009
+ style: { width: "100%", height: "100%", minHeight: "560px", border: "none", ...style },
1010
+ allowFullScreen,
1011
+ title: "Orkid Swap"
1012
+ }
1013
+ );
1014
+ }
1015
+
1016
+ // src/embed.ts
1017
+ var import_react7 = require("react");
1018
+ var import_client = require("react-dom/client");
1019
+ function mountOrkidSwap(options) {
1020
+ const { target, ...props } = options;
1021
+ const el = typeof target === "string" ? document.querySelector(target) : target;
1022
+ if (!el) throw new Error(`OrkidSwap: target element not found: ${target}`);
1023
+ const root = (0, import_client.createRoot)(el);
1024
+ root.render(
1025
+ (0, import_react7.createElement)(OrkidSwapProvider, props, (0, import_react7.createElement)(OrkidSwapWidget))
1026
+ );
1027
+ return () => root.unmount();
1028
+ }
1029
+ // Annotate the CommonJS export names for ESM import in node:
1030
+ 0 && (module.exports = {
1031
+ OrkidSwapContext,
1032
+ OrkidSwapIframe,
1033
+ OrkidSwapProvider,
1034
+ OrkidSwapWidget,
1035
+ defaultDarkTheme,
1036
+ defaultLightTheme,
1037
+ mountOrkidSwap,
1038
+ resolveTheme,
1039
+ themeToCssVariables,
1040
+ useOrkidSwapContext
1041
+ });
1042
+ //# sourceMappingURL=index.js.map