otx-swap 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,73 +1,467 @@
1
- # React + TypeScript + Vite
1
+ # OTX Swap Widget
2
2
 
3
- This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
3
+ A lightweight, customizable React widget for cross-chain token swaps powered by Optimex protocol.
4
4
 
5
- Currently, two official plugins are available:
5
+ ## Features
6
6
 
7
- - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8
- - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
7
+ - Cross-chain swaps between EVM, Bitcoin, and Solana networks
8
+ - Bring Your Own Wallet (BYOW) - integrate with your existing wallet infrastructure
9
+ - Fully customizable theming
10
+ - TypeScript support with full type definitions
11
+ - Lightweight bundle (~313KB gzipped: ~72KB)
12
+ - Lifecycle callbacks for tracking swap progress
9
13
 
10
- ## React Compiler
14
+ ## Installation
11
15
 
12
- The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
16
+ ```bash
17
+ npm install otx-swap
18
+ # or
19
+ yarn add otx-swap
20
+ # or
21
+ pnpm add otx-swap
22
+ ```
13
23
 
14
- ## Expanding the ESLint configuration
24
+ ### Peer Dependencies
15
25
 
16
- If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
26
+ ```bash
27
+ npm install react react-dom
28
+ ```
17
29
 
18
- ```js
19
- export default defineConfig([
20
- globalIgnores(['dist']),
21
- {
22
- files: ['**/*.{ts,tsx}'],
23
- extends: [
24
- // Other configs...
30
+ ## Quick Start
25
31
 
26
- // Remove tseslint.configs.recommended and replace with this
27
- tseslint.configs.recommendedTypeChecked,
28
- // Alternatively, use this for stricter rules
29
- tseslint.configs.strictTypeChecked,
30
- // Optionally, add this for stylistic rules
31
- tseslint.configs.stylisticTypeChecked,
32
+ ```tsx
33
+ import { SwapWidget } from "otx-swap";
34
+ import type { ExternalWalletClient } from "otx-swap";
32
35
 
33
- // Other configs...
34
- ],
35
- languageOptions: {
36
- parserOptions: {
37
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
38
- tsconfigRootDir: import.meta.dirname,
36
+ function App() {
37
+ // Build wallet client from your wallet provider
38
+ const walletClient: ExternalWalletClient = {
39
+ evm: {
40
+ address: "0x...",
41
+ publicKey: "0x...",
42
+ chain: { id: 1, name: "Ethereum", type: "EVM" },
43
+ sendTransaction: async (tx) => {
44
+ // Your wallet's sendTransaction implementation
45
+ return txHash;
46
+ },
47
+ getChainId: async () => 1,
48
+ switchChain: async (chainId) => {
49
+ // Your wallet's switchChain implementation
39
50
  },
40
- // other options...
41
51
  },
42
- },
43
- ])
44
- ```
45
-
46
- You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47
-
48
- ```js
49
- // eslint.config.js
50
- import reactX from 'eslint-plugin-react-x'
51
- import reactDom from 'eslint-plugin-react-dom'
52
-
53
- export default defineConfig([
54
- globalIgnores(['dist']),
55
- {
56
- files: ['**/*.{ts,tsx}'],
57
- extends: [
58
- // Other configs...
59
- // Enable lint rules for React
60
- reactX.configs['recommended-typescript'],
61
- // Enable lint rules for React DOM
62
- reactDom.configs.recommended,
63
- ],
64
- languageOptions: {
65
- parserOptions: {
66
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
67
- tsconfigRootDir: import.meta.dirname,
52
+ };
53
+
54
+ return (
55
+ <SwapWidget
56
+ apiBaseUrl="https://api.optimex.io"
57
+ walletClient={walletClient}
58
+ onRequestWallet={(networkId) => {
59
+ // Called when user needs to connect wallet
60
+ console.log("Connect wallet for network:", networkId);
61
+ }}
62
+ />
63
+ );
64
+ }
65
+ ```
66
+
67
+ ## API Reference
68
+
69
+ ### SwapWidget Props
70
+
71
+ | Prop | Type | Required | Default | Description |
72
+ |------|------|----------|---------|-------------|
73
+ | `apiBaseUrl` | `string` | Yes | - | Optimex API base URL |
74
+ | `walletClient` | `ExternalWalletClient` | Yes | - | Connected wallet client object |
75
+ | `onRequestWallet` | `(networkId?: string) => void` | No | - | Callback when wallet connection is needed |
76
+ | `theme` | `PartialThemeConfig` | No | - | Custom theme configuration |
77
+ | `defaultFromToken` | `string` | No | - | Default source token ID |
78
+ | `defaultToToken` | `string` | No | - | Default destination token ID |
79
+ | `defaultSlippage` | `number` | No | `0.75` | Default slippage tolerance (%) |
80
+ | `hideHistory` | `boolean` | No | `false` | Hide transaction history button |
81
+ | `affiliateFee` | `number` | No | - | Affiliate fee in basis points |
82
+ | `affiliateAddress` | `string` | No | - | Affiliate fee recipient address |
83
+ | `affiliateProvider` | `string` | No | - | Affiliate provider identifier |
84
+ | `tradeTimeout` | `number` | No | - | Trade timeout in minutes |
85
+ | `scriptTimeout` | `number` | No | - | Script timeout in minutes |
86
+ | `queryClient` | `QueryClient` | No | - | Shared React Query client |
87
+ | `renderLoading` | `ComponentType` | No | - | Custom loading component |
88
+ | `renderError` | `ComponentType` | No | - | Custom error component |
89
+ | `children` | `ReactNode` | No | - | Custom content instead of default SwapCard |
90
+
91
+ ### Lifecycle Callbacks
92
+
93
+ Track swap progress with these callbacks:
94
+
95
+ ```tsx
96
+ <SwapWidget
97
+ apiBaseUrl="https://api.optimex.io"
98
+ walletClient={walletClient}
99
+ onQuote={(data) => {
100
+ // Called when quote is received
101
+ console.log("Quote received:", data.quote.trade_id);
102
+ }}
103
+ onWalletTx={(data) => {
104
+ // Called when wallet transaction is sent
105
+ console.log("Wallet TX:", data.tx_hash);
106
+ }}
107
+ onSubmitTx={(data) => {
108
+ // Called when transaction is submitted to network
109
+ console.log("Submit TX status:", data.status);
110
+ }}
111
+ onSwapComplete={(data) => {
112
+ // Called when swap is completed successfully
113
+ console.log("Swap complete:", data.trade.trade_id);
114
+ }}
115
+ onError={(data) => {
116
+ // Called when an error occurs
117
+ console.error("Error at stage:", data.stage, data.error);
118
+ }}
119
+ />
120
+ ```
121
+
122
+ #### Callback Types
123
+
124
+ ```typescript
125
+ interface QuoteCallbackData {
126
+ quote: Quote;
127
+ from_token: Token;
128
+ to_token: Token;
129
+ amount_in: string;
130
+ }
131
+
132
+ interface WalletTxCallbackData {
133
+ trade_id: string;
134
+ tx_hash: string;
135
+ from_token: Token;
136
+ to_token: Token;
137
+ amount_in: string;
138
+ }
139
+
140
+ interface SubmitTxCallbackData {
141
+ trade_id: string;
142
+ tx_hash: string;
143
+ status: "success" | "error";
144
+ error?: string;
145
+ }
146
+
147
+ interface SwapCompleteCallbackData {
148
+ trade: Trade;
149
+ tx_hash: string;
150
+ }
151
+
152
+ interface SwapErrorCallbackData {
153
+ error: Error;
154
+ stage: "quote" | "approval" | "wallet_tx" | "submit_tx" | "tracking";
155
+ trade_id?: string;
156
+ }
157
+ ```
158
+
159
+ ## Wallet Integration
160
+
161
+ ### ExternalWalletClient Interface
162
+
163
+ The widget requires a wallet client that implements the `ExternalWalletClient` interface:
164
+
165
+ ```typescript
166
+ interface ExternalWalletClient {
167
+ evm?: EvmWalletAccount; // EVM wallet (Ethereum, Polygon, etc.)
168
+ btc?: WalletAccount; // Bitcoin wallet
169
+ solana?: WalletAccount; // Solana wallet
170
+ }
171
+ ```
172
+
173
+ ### EVM Wallet
174
+
175
+ ```typescript
176
+ interface EvmWalletAccount {
177
+ address: string;
178
+ publicKey: string;
179
+ chain: {
180
+ id: number;
181
+ name: string;
182
+ type: "EVM";
183
+ };
184
+ sendTransaction: (tx: EvmTransactionRequest) => Promise<string>;
185
+ getChainId: () => Promise<number>;
186
+ switchChain: (chainId: number) => Promise<void>;
187
+ }
188
+
189
+ interface EvmTransactionRequest {
190
+ to: `0x${string}`;
191
+ value?: bigint;
192
+ data?: `0x${string}`;
193
+ chainId?: number;
194
+ }
195
+ ```
196
+
197
+ ### Bitcoin Wallet
198
+
199
+ ```typescript
200
+ interface WalletAccount {
201
+ address: string;
202
+ publicKey: string; // BTC public key (different from address)
203
+ chain: {
204
+ id: string; // "mainnet" or "testnet"
205
+ name: string;
206
+ type: "BTC";
207
+ };
208
+ sendTransaction: (tx: BitcoinTransactionRequest) => Promise<string>;
209
+ }
210
+
211
+ interface BitcoinTransactionRequest {
212
+ toAddress: string;
213
+ amount: bigint;
214
+ options?: {
215
+ feeRate?: number;
216
+ memo?: string;
217
+ memos?: string[];
218
+ };
219
+ }
220
+ ```
221
+
222
+ ### Solana Wallet
223
+
224
+ ```typescript
225
+ interface WalletAccount {
226
+ address: string;
227
+ publicKey: string;
228
+ chain: {
229
+ id: string;
230
+ name: string;
231
+ type: "Solana";
232
+ };
233
+ sendTransaction: (tx: unknown) => Promise<string>;
234
+ }
235
+ ```
236
+
237
+ ### Integration Examples
238
+
239
+ #### With wagmi (EVM)
240
+
241
+ ```tsx
242
+ import { useAccount, useSendTransaction, useChainId, useSwitchChain } from "wagmi";
243
+ import { SwapWidget } from "otx-swap";
244
+ import type { ExternalWalletClient, EvmTransactionRequest } from "otx-swap";
245
+
246
+ function SwapWithWagmi() {
247
+ const { address, isConnected } = useAccount();
248
+ const chainId = useChainId();
249
+ const { sendTransactionAsync } = useSendTransaction();
250
+ const { switchChainAsync } = useSwitchChain();
251
+
252
+ const walletClient: ExternalWalletClient = {
253
+ evm: isConnected && address ? {
254
+ address,
255
+ publicKey: address,
256
+ chain: { id: chainId, name: "Ethereum", type: "EVM" },
257
+ sendTransaction: async (tx: unknown) => {
258
+ const evmTx = tx as EvmTransactionRequest;
259
+ return sendTransactionAsync({
260
+ to: evmTx.to,
261
+ value: evmTx.value,
262
+ data: evmTx.data,
263
+ });
68
264
  },
69
- // other options...
265
+ getChainId: async () => chainId,
266
+ switchChain: async (id) => {
267
+ await switchChainAsync({ chainId: id });
268
+ },
269
+ } : undefined,
270
+ };
271
+
272
+ return (
273
+ <SwapWidget
274
+ apiBaseUrl="https://api.optimex.io"
275
+ walletClient={walletClient}
276
+ />
277
+ );
278
+ }
279
+ ```
280
+
281
+ #### With Unisat (Bitcoin)
282
+
283
+ ```tsx
284
+ import { SwapWidget } from "otx-swap";
285
+ import type { ExternalWalletClient, BitcoinTransactionRequest } from "otx-swap";
286
+
287
+ function SwapWithUnisat() {
288
+ const [btcAddress, setBtcAddress] = useState<string | null>(null);
289
+ const [btcPublicKey, setBtcPublicKey] = useState<string | null>(null);
290
+
291
+ const connectUnisat = async () => {
292
+ const unisat = (window as any).unisat;
293
+ const accounts = await unisat.requestAccounts();
294
+ const pubKey = await unisat.getPublicKey();
295
+ setBtcAddress(accounts[0]);
296
+ setBtcPublicKey(pubKey);
297
+ };
298
+
299
+ const walletClient: ExternalWalletClient = {
300
+ btc: btcAddress && btcPublicKey ? {
301
+ address: btcAddress,
302
+ publicKey: btcPublicKey,
303
+ chain: { id: "mainnet", name: "Bitcoin", type: "BTC" },
304
+ sendTransaction: async (tx: unknown) => {
305
+ const btcTx = tx as BitcoinTransactionRequest;
306
+ const unisat = (window as any).unisat;
307
+ return unisat.sendBitcoin(btcTx.toAddress, Number(btcTx.amount));
308
+ },
309
+ } : undefined,
310
+ };
311
+
312
+ return (
313
+ <SwapWidget
314
+ apiBaseUrl="https://api.optimex.io"
315
+ walletClient={walletClient}
316
+ onRequestWallet={() => connectUnisat()}
317
+ />
318
+ );
319
+ }
320
+ ```
321
+
322
+ ## Theming
323
+
324
+ Customize the widget appearance with the `theme` prop:
325
+
326
+ ```tsx
327
+ <SwapWidget
328
+ apiBaseUrl="https://api.optimex.io"
329
+ walletClient={walletClient}
330
+ theme={{
331
+ colors: {
332
+ primary: "#3B82F6",
333
+ primaryHover: "#2563EB",
334
+ background: "#0F172A",
335
+ surface: "#1E293B",
336
+ surfaceHover: "#334155",
337
+ text: "#F8FAFC",
338
+ textSecondary: "#94A3B8",
339
+ border: "#334155",
340
+ success: "#22C55E",
341
+ error: "#EF4444",
342
+ warning: "#F59E0B",
70
343
  },
71
- },
72
- ])
344
+ borderRadius: "md", // "none" | "sm" | "md" | "lg" | "full"
345
+ fontFamily: "Inter, sans-serif",
346
+ }}
347
+ />
348
+ ```
349
+
350
+ ### Theme Colors
351
+
352
+ | Color | Description |
353
+ |-------|-------------|
354
+ | `primary` | Primary action color (buttons, links) |
355
+ | `primaryHover` | Primary color on hover |
356
+ | `secondary` | Secondary accent color |
357
+ | `background` | Widget background color |
358
+ | `surface` | Card/panel background color |
359
+ | `surfaceHover` | Surface color on hover |
360
+ | `text` | Primary text color |
361
+ | `textSecondary` | Secondary/muted text color |
362
+ | `border` | Border color |
363
+ | `success` | Success state color |
364
+ | `error` | Error state color |
365
+ | `warning` | Warning state color |
366
+
367
+ ## Custom Components
368
+
369
+ ### Custom Loading Component
370
+
371
+ ```tsx
372
+ import { SwapWidget } from "otx-swap";
373
+ import type { CustomLoadingProps } from "otx-swap";
374
+
375
+ function MyLoadingSpinner({ className }: CustomLoadingProps) {
376
+ return (
377
+ <div className={className}>
378
+ <span>Loading...</span>
379
+ </div>
380
+ );
381
+ }
382
+
383
+ <SwapWidget
384
+ apiBaseUrl="https://api.optimex.io"
385
+ walletClient={walletClient}
386
+ renderLoading={MyLoadingSpinner}
387
+ />
388
+ ```
389
+
390
+ ### Custom Error Component
391
+
392
+ ```tsx
393
+ import type { CustomErrorProps } from "otx-swap";
394
+
395
+ function MyErrorComponent({ error, onRetry, className }: CustomErrorProps) {
396
+ return (
397
+ <div className={className}>
398
+ <p>Error: {error?.message}</p>
399
+ <button onClick={onRetry}>Retry</button>
400
+ </div>
401
+ );
402
+ }
403
+
404
+ <SwapWidget
405
+ apiBaseUrl="https://api.optimex.io"
406
+ walletClient={walletClient}
407
+ renderError={MyErrorComponent}
408
+ />
409
+ ```
410
+
411
+ ## Standalone Components
412
+
413
+ The widget also exports standalone components for custom layouts:
414
+
415
+ ```tsx
416
+ import { SwapCard, ConnectButton, useWallet } from "otx-swap";
417
+
418
+ // Use ConnectButton separately
419
+ <ConnectButton
420
+ connectLabel="Connect Wallet"
421
+ showNetworkBadge={true}
422
+ onClick={() => {
423
+ // Custom connect logic
424
+ }}
425
+ />
426
+ ```
427
+
428
+ ## TypeScript
429
+
430
+ Full TypeScript support with exported types:
431
+
432
+ ```tsx
433
+ import type {
434
+ SwapWidgetProps,
435
+ ExternalWalletClient,
436
+ WalletAccount,
437
+ EvmWalletAccount,
438
+ EvmTransactionRequest,
439
+ BitcoinTransactionRequest,
440
+ ChainInfo,
441
+ Token,
442
+ Quote,
443
+ Trade,
444
+ TradeState,
445
+ NetworkType,
446
+ ThemeConfig,
447
+ PartialThemeConfig,
448
+ ThemeColors,
449
+ QuoteCallbackData,
450
+ WalletTxCallbackData,
451
+ SubmitTxCallbackData,
452
+ SwapCompleteCallbackData,
453
+ SwapErrorCallbackData,
454
+ SwapCallbacks,
455
+ } from "otx-swap";
73
456
  ```
457
+
458
+ ## Browser Support
459
+
460
+ - Chrome 80+
461
+ - Firefox 75+
462
+ - Safari 13+
463
+ - Edge 80+
464
+
465
+ ## License
466
+
467
+ MIT