otx-swap 1.2.1 → 1.2.3
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 +452 -58
- package/dist/index.cjs +9 -9
- package/dist/index.mjs +2065 -2053
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -1,73 +1,467 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OTX Swap Widget
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A lightweight, customizable React widget for cross-chain token swaps powered by Optimex protocol.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
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
|
-
##
|
|
14
|
+
## Installation
|
|
11
15
|
|
|
12
|
-
|
|
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
|
-
|
|
24
|
+
### Peer Dependencies
|
|
15
25
|
|
|
16
|
-
|
|
26
|
+
```bash
|
|
27
|
+
npm install react react-dom
|
|
28
|
+
```
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
export default defineConfig([
|
|
20
|
-
globalIgnores(['dist']),
|
|
21
|
-
{
|
|
22
|
-
files: ['**/*.{ts,tsx}'],
|
|
23
|
-
extends: [
|
|
24
|
-
// Other configs...
|
|
30
|
+
## Quick Start
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
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
|