@one_deploy/sdk 1.0.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/.turbo/turbo-build.log +0 -0
- package/.turbo/turbo-type-check.log +0 -0
- package/dist/config/index.d.mts +74 -0
- package/dist/config/index.d.ts +74 -0
- package/dist/config/index.js +242 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +224 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/engine-5ndtBaCr.d.ts +1039 -0
- package/dist/engine-CrlhH0nw.d.mts +1039 -0
- package/dist/hooks/index.d.mts +56 -0
- package/dist/hooks/index.d.ts +56 -0
- package/dist/hooks/index.js +1360 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/index.mjs +1356 -0
- package/dist/hooks/index.mjs.map +1 -0
- package/dist/index.d.mts +356 -0
- package/dist/index.d.ts +356 -0
- package/dist/index.js +5068 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4949 -0
- package/dist/index.mjs.map +1 -0
- package/dist/price-CgqXPnT3.d.ts +13 -0
- package/dist/price-ClbLHHjv.d.mts +13 -0
- package/dist/providers/index.d.mts +121 -0
- package/dist/providers/index.d.ts +121 -0
- package/dist/providers/index.js +1642 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/index.mjs +1600 -0
- package/dist/providers/index.mjs.map +1 -0
- package/dist/react-native.d.mts +120 -0
- package/dist/react-native.d.ts +120 -0
- package/dist/react-native.js +1792 -0
- package/dist/react-native.js.map +1 -0
- package/dist/react-native.mjs +1755 -0
- package/dist/react-native.mjs.map +1 -0
- package/dist/services/index.d.mts +85 -0
- package/dist/services/index.d.ts +85 -0
- package/dist/services/index.js +1466 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/index.mjs +1458 -0
- package/dist/services/index.mjs.map +1 -0
- package/dist/types/index.d.mts +759 -0
- package/dist/types/index.d.ts +759 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.mjs +3 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/utils/index.d.mts +36 -0
- package/dist/utils/index.d.ts +36 -0
- package/dist/utils/index.js +164 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +142 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +101 -0
- package/src/components/OneConnectButton.tsx +143 -0
- package/src/components/OneNFTGallery.tsx +324 -0
- package/src/components/OneOfframpWidget.tsx +660 -0
- package/src/components/OneOnrampWidget.tsx +596 -0
- package/src/components/OnePayWidget.tsx +160 -0
- package/src/components/OneReceiveWidget.tsx +272 -0
- package/src/components/OneSendWidget.tsx +248 -0
- package/src/components/OneSwapWidget.tsx +715 -0
- package/src/components/OneTransactionButton.tsx +150 -0
- package/src/components/OneWalletBalance.tsx +354 -0
- package/src/components/index.ts +24 -0
- package/src/config/index.ts +299 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTokenPrice.ts +162 -0
- package/src/hooks/useWalletBalance.ts +98 -0
- package/src/index.ts +193 -0
- package/src/providers/OneProvider.tsx +452 -0
- package/src/providers/ThirdwebProvider.tsx +203 -0
- package/src/providers/index.ts +26 -0
- package/src/react-native.ts +378 -0
- package/src/services/engine.ts +1854 -0
- package/src/services/index.ts +30 -0
- package/src/services/price.ts +164 -0
- package/src/services/supabase.ts +180 -0
- package/src/types/index.ts +887 -0
- package/src/utils/index.ts +200 -0
- package/tsconfig.json +22 -0
- package/tsup.config.ts +25 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4949 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js';
|
|
2
|
+
import React2, { createContext, useState, useMemo, useEffect, useCallback, useContext, useRef } from 'react';
|
|
3
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
4
|
+
import { createThirdwebClient, prepareTransaction, toWei } from 'thirdweb';
|
|
5
|
+
import { ThirdwebProvider, ConnectButton, PayEmbed, TransactionButton, useActiveAccount, useSendTransaction, useWalletBalance, MediaRenderer } from 'thirdweb/react';
|
|
6
|
+
import { inAppWallet, smartWallet } from 'thirdweb/wallets';
|
|
7
|
+
export { inAppWallet, smartWallet } from 'thirdweb/wallets';
|
|
8
|
+
import { arbitrum, polygon, ethereum, base, optimism, bsc, avalanche } from 'thirdweb/chains';
|
|
9
|
+
export { arbitrum, base, ethereum, optimism, polygon } from 'thirdweb/chains';
|
|
10
|
+
|
|
11
|
+
// src/config/index.ts
|
|
12
|
+
var config = null;
|
|
13
|
+
function initOneSDK(options) {
|
|
14
|
+
if (!options.oneEngineUrl) {
|
|
15
|
+
throw new Error("oneEngineUrl is required");
|
|
16
|
+
}
|
|
17
|
+
if (!options.oneClientId) {
|
|
18
|
+
throw new Error("oneClientId is required");
|
|
19
|
+
}
|
|
20
|
+
config = options;
|
|
21
|
+
}
|
|
22
|
+
function getConfig() {
|
|
23
|
+
if (!config) {
|
|
24
|
+
throw new Error("ONE SDK not initialized. Call initOneSDK() first.");
|
|
25
|
+
}
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
function isInitialized() {
|
|
29
|
+
return config !== null;
|
|
30
|
+
}
|
|
31
|
+
function getEngineUrl() {
|
|
32
|
+
return config?.oneEngineUrl || process.env.NEXT_PUBLIC_ONE_ENGINE_URL || "http://localhost:4000/api";
|
|
33
|
+
}
|
|
34
|
+
var chainsCache = null;
|
|
35
|
+
var chainsCacheTimestamp = 0;
|
|
36
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
37
|
+
async function fetchChains(options) {
|
|
38
|
+
const engineUrl = getEngineUrl();
|
|
39
|
+
const params = new URLSearchParams();
|
|
40
|
+
if (options?.category) params.set("category", options.category);
|
|
41
|
+
if (options?.smartWallet) params.set("smartWallet", "true");
|
|
42
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
43
|
+
const response = await fetch(`${engineUrl}/v1/chains?${params}`);
|
|
44
|
+
const data = await response.json();
|
|
45
|
+
if (!data.success) {
|
|
46
|
+
throw new Error(data.error?.message || "Failed to fetch chains");
|
|
47
|
+
}
|
|
48
|
+
return data.data.chains.map((chain) => ({
|
|
49
|
+
id: chain.id,
|
|
50
|
+
name: chain.name,
|
|
51
|
+
shortName: chain.shortName || chain.slug || chain.name.toLowerCase(),
|
|
52
|
+
icon: getChainIcon(chain.id),
|
|
53
|
+
nativeCurrency: chain.nativeCurrency,
|
|
54
|
+
rpcUrls: Array.isArray(chain.rpc) ? chain.rpc : [chain.rpc],
|
|
55
|
+
blockExplorerUrls: chain.blockExplorer ? [chain.blockExplorer] : [],
|
|
56
|
+
testnet: chain.testnet
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
async function getChains() {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
if (chainsCache && now - chainsCacheTimestamp < CACHE_TTL) {
|
|
62
|
+
return chainsCache;
|
|
63
|
+
}
|
|
64
|
+
chainsCache = await fetchChains({ limit: 200 });
|
|
65
|
+
chainsCacheTimestamp = now;
|
|
66
|
+
return chainsCache;
|
|
67
|
+
}
|
|
68
|
+
async function getChainById(chainId) {
|
|
69
|
+
const chains = await getChains();
|
|
70
|
+
return chains.find((c) => c.id === chainId);
|
|
71
|
+
}
|
|
72
|
+
async function getChainByName(name) {
|
|
73
|
+
const chains = await getChains();
|
|
74
|
+
const lowerName = name.toLowerCase();
|
|
75
|
+
return chains.find(
|
|
76
|
+
(c) => c.name.toLowerCase() === lowerName || c.shortName.toLowerCase() === lowerName
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
async function getRecommendedChains() {
|
|
80
|
+
return fetchChains({ category: "recommended", limit: 10 });
|
|
81
|
+
}
|
|
82
|
+
async function getSmartWalletChains() {
|
|
83
|
+
return fetchChains({ smartWallet: true, limit: 50 });
|
|
84
|
+
}
|
|
85
|
+
var CHAIN_IDS = {
|
|
86
|
+
ETHEREUM: 1,
|
|
87
|
+
POLYGON: 137,
|
|
88
|
+
BSC: 56,
|
|
89
|
+
ARBITRUM: 42161,
|
|
90
|
+
OPTIMISM: 10,
|
|
91
|
+
BASE: 8453,
|
|
92
|
+
AVALANCHE: 43114,
|
|
93
|
+
ZKSYNC: 324,
|
|
94
|
+
LINEA: 59144,
|
|
95
|
+
SCROLL: 534352,
|
|
96
|
+
BLAST: 81457,
|
|
97
|
+
// Testnets
|
|
98
|
+
SEPOLIA: 11155111,
|
|
99
|
+
BASE_SEPOLIA: 84532,
|
|
100
|
+
ARBITRUM_SEPOLIA: 421614
|
|
101
|
+
};
|
|
102
|
+
var DEFAULT_CHAIN_ID = CHAIN_IDS.BASE;
|
|
103
|
+
var CHAIN_ICONS = {
|
|
104
|
+
1: "\u229F",
|
|
105
|
+
// Ethereum
|
|
106
|
+
137: "\u{1F7E3}",
|
|
107
|
+
// Polygon
|
|
108
|
+
56: "\u{1F7E1}",
|
|
109
|
+
// BSC
|
|
110
|
+
42161: "\u{1F535}",
|
|
111
|
+
// Arbitrum
|
|
112
|
+
10: "\u{1F534}",
|
|
113
|
+
// Optimism
|
|
114
|
+
8453: "\u{1F537}",
|
|
115
|
+
// Base
|
|
116
|
+
43114: "\u{1F53A}",
|
|
117
|
+
// Avalanche
|
|
118
|
+
324: "\u26A1",
|
|
119
|
+
// zkSync
|
|
120
|
+
59144: "\u{1F539}",
|
|
121
|
+
// Linea
|
|
122
|
+
534352: "\u{1F4DC}"
|
|
123
|
+
// Scroll
|
|
124
|
+
};
|
|
125
|
+
function getChainIcon(chainId) {
|
|
126
|
+
return CHAIN_ICONS[chainId] || "\u{1F517}";
|
|
127
|
+
}
|
|
128
|
+
var TOKEN_NAMES = {
|
|
129
|
+
ETH: "Ethereum",
|
|
130
|
+
BTC: "Bitcoin",
|
|
131
|
+
BNB: "BNB",
|
|
132
|
+
MATIC: "Polygon",
|
|
133
|
+
POL: "Polygon",
|
|
134
|
+
AVAX: "Avalanche",
|
|
135
|
+
USDT: "Tether",
|
|
136
|
+
USDC: "USD Coin",
|
|
137
|
+
DAI: "Dai",
|
|
138
|
+
WBTC: "Wrapped Bitcoin",
|
|
139
|
+
WETH: "Wrapped Ether",
|
|
140
|
+
ARB: "Arbitrum",
|
|
141
|
+
OP: "Optimism",
|
|
142
|
+
LINK: "Chainlink",
|
|
143
|
+
UNI: "Uniswap",
|
|
144
|
+
AAVE: "Aave",
|
|
145
|
+
CRV: "Curve",
|
|
146
|
+
MKR: "Maker",
|
|
147
|
+
SNX: "Synthetix",
|
|
148
|
+
COMP: "Compound",
|
|
149
|
+
SUSHI: "SushiSwap",
|
|
150
|
+
YFI: "Yearn Finance",
|
|
151
|
+
SOL: "Solana",
|
|
152
|
+
DOT: "Polkadot",
|
|
153
|
+
ATOM: "Cosmos",
|
|
154
|
+
NEAR: "Near Protocol"
|
|
155
|
+
};
|
|
156
|
+
var COINGECKO_IDS = {
|
|
157
|
+
ETH: "ethereum",
|
|
158
|
+
BTC: "bitcoin",
|
|
159
|
+
BNB: "binancecoin",
|
|
160
|
+
MATIC: "matic-network",
|
|
161
|
+
POL: "matic-network",
|
|
162
|
+
AVAX: "avalanche-2",
|
|
163
|
+
USDT: "tether",
|
|
164
|
+
USDC: "usd-coin",
|
|
165
|
+
DAI: "dai",
|
|
166
|
+
WBTC: "wrapped-bitcoin",
|
|
167
|
+
WETH: "weth",
|
|
168
|
+
ARB: "arbitrum",
|
|
169
|
+
OP: "optimism",
|
|
170
|
+
LINK: "chainlink",
|
|
171
|
+
UNI: "uniswap",
|
|
172
|
+
AAVE: "aave",
|
|
173
|
+
SOL: "solana"
|
|
174
|
+
};
|
|
175
|
+
var CHAIN_CONFIGS = {
|
|
176
|
+
ethereum: {
|
|
177
|
+
id: 1,
|
|
178
|
+
name: "Ethereum",
|
|
179
|
+
shortName: "ETH",
|
|
180
|
+
icon: "\u229F",
|
|
181
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
182
|
+
rpcUrls: ["https://ethereum.rpc.thirdweb.com"],
|
|
183
|
+
blockExplorerUrls: ["https://etherscan.io"],
|
|
184
|
+
testnet: false
|
|
185
|
+
},
|
|
186
|
+
polygon: {
|
|
187
|
+
id: 137,
|
|
188
|
+
name: "Polygon",
|
|
189
|
+
shortName: "MATIC",
|
|
190
|
+
icon: "\u{1F7E3}",
|
|
191
|
+
nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
|
|
192
|
+
rpcUrls: ["https://polygon.rpc.thirdweb.com"],
|
|
193
|
+
blockExplorerUrls: ["https://polygonscan.com"],
|
|
194
|
+
testnet: false
|
|
195
|
+
},
|
|
196
|
+
base: {
|
|
197
|
+
id: 8453,
|
|
198
|
+
name: "Base",
|
|
199
|
+
shortName: "BASE",
|
|
200
|
+
icon: "\u{1F537}",
|
|
201
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
202
|
+
rpcUrls: ["https://base.rpc.thirdweb.com"],
|
|
203
|
+
blockExplorerUrls: ["https://basescan.org"],
|
|
204
|
+
testnet: false
|
|
205
|
+
},
|
|
206
|
+
arbitrum: {
|
|
207
|
+
id: 42161,
|
|
208
|
+
name: "Arbitrum One",
|
|
209
|
+
shortName: "ARB",
|
|
210
|
+
icon: "\u{1F535}",
|
|
211
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
212
|
+
rpcUrls: ["https://arbitrum.rpc.thirdweb.com"],
|
|
213
|
+
blockExplorerUrls: ["https://arbiscan.io"],
|
|
214
|
+
testnet: false
|
|
215
|
+
},
|
|
216
|
+
optimism: {
|
|
217
|
+
id: 10,
|
|
218
|
+
name: "Optimism",
|
|
219
|
+
shortName: "OP",
|
|
220
|
+
icon: "\u{1F534}",
|
|
221
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
222
|
+
rpcUrls: ["https://optimism.rpc.thirdweb.com"],
|
|
223
|
+
blockExplorerUrls: ["https://optimistic.etherscan.io"],
|
|
224
|
+
testnet: false
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
var SUPPORTED_CHAINS = Object.keys(CHAIN_CONFIGS);
|
|
228
|
+
function getChainConfig(chain) {
|
|
229
|
+
return CHAIN_CONFIGS[chain.toLowerCase()];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/services/engine.ts
|
|
233
|
+
var OneEngineClient = class {
|
|
234
|
+
constructor(options) {
|
|
235
|
+
const config2 = getConfig();
|
|
236
|
+
this.baseUrl = options?.baseUrl || config2.oneEngineUrl;
|
|
237
|
+
this.clientId = options?.clientId || config2.oneClientId || "";
|
|
238
|
+
this.secretKey = options?.secretKey || config2.oneSecretKey;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Set access token for authenticated requests
|
|
242
|
+
*/
|
|
243
|
+
setAccessToken(token) {
|
|
244
|
+
this.accessToken = token;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Clear access token
|
|
248
|
+
*/
|
|
249
|
+
clearAccessToken() {
|
|
250
|
+
this.accessToken = void 0;
|
|
251
|
+
}
|
|
252
|
+
getHeaders(includeSecret = false) {
|
|
253
|
+
const headers = {
|
|
254
|
+
"Content-Type": "application/json",
|
|
255
|
+
"x-client-id": this.clientId
|
|
256
|
+
};
|
|
257
|
+
if (this.accessToken) {
|
|
258
|
+
headers["Authorization"] = `Bearer ${this.accessToken}`;
|
|
259
|
+
}
|
|
260
|
+
if (includeSecret && this.secretKey) {
|
|
261
|
+
headers["x-secret-key"] = this.secretKey;
|
|
262
|
+
}
|
|
263
|
+
return headers;
|
|
264
|
+
}
|
|
265
|
+
async request(endpoint, options = {}, includeSecret = false) {
|
|
266
|
+
try {
|
|
267
|
+
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
268
|
+
...options,
|
|
269
|
+
headers: {
|
|
270
|
+
...this.getHeaders(includeSecret),
|
|
271
|
+
...options.headers
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
const data = await response.json();
|
|
275
|
+
if (!response.ok) {
|
|
276
|
+
return {
|
|
277
|
+
success: false,
|
|
278
|
+
error: {
|
|
279
|
+
code: data.error?.code || `HTTP_${response.status}`,
|
|
280
|
+
message: data.error?.message || "Request failed"
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
success: true,
|
|
286
|
+
data: data.data || data
|
|
287
|
+
};
|
|
288
|
+
} catch (error) {
|
|
289
|
+
return {
|
|
290
|
+
success: false,
|
|
291
|
+
error: {
|
|
292
|
+
code: "NETWORK_ERROR",
|
|
293
|
+
message: error instanceof Error ? error.message : "Network request failed"
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// ===============================
|
|
299
|
+
// AUTH ENDPOINTS
|
|
300
|
+
// ===============================
|
|
301
|
+
/**
|
|
302
|
+
* Send OTP to email for authentication
|
|
303
|
+
*/
|
|
304
|
+
async sendEmailOtp(email) {
|
|
305
|
+
return this.request("/api/v1/auth/otp", {
|
|
306
|
+
method: "POST",
|
|
307
|
+
body: JSON.stringify({ email })
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Verify OTP and get access token
|
|
312
|
+
*/
|
|
313
|
+
async verifyEmailOtp(email, otp) {
|
|
314
|
+
return this.request("/api/v1/auth/otp/verify", {
|
|
315
|
+
method: "POST",
|
|
316
|
+
body: JSON.stringify({ email, otp })
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Authenticate with wallet signature
|
|
321
|
+
*/
|
|
322
|
+
async authWithWallet(walletAddress, signature, message) {
|
|
323
|
+
return this.request("/api/v1/auth/wallet", {
|
|
324
|
+
method: "POST",
|
|
325
|
+
body: JSON.stringify({ walletAddress, signature, message })
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Refresh access token
|
|
330
|
+
*/
|
|
331
|
+
async refreshToken(refreshToken) {
|
|
332
|
+
return this.request("/api/v1/auth/refresh", {
|
|
333
|
+
method: "POST",
|
|
334
|
+
body: JSON.stringify({ refreshToken })
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get current user
|
|
339
|
+
*/
|
|
340
|
+
async getCurrentUser() {
|
|
341
|
+
return this.request("/api/v1/auth/me", { method: "GET" });
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Sign out
|
|
345
|
+
*/
|
|
346
|
+
async signOut() {
|
|
347
|
+
return this.request("/api/v1/auth/logout", { method: "POST" });
|
|
348
|
+
}
|
|
349
|
+
// ===============================
|
|
350
|
+
// WALLET/ASSETS ENDPOINTS
|
|
351
|
+
// ===============================
|
|
352
|
+
/**
|
|
353
|
+
* Get wallet balance across all chains
|
|
354
|
+
*/
|
|
355
|
+
async getWalletBalance(walletAddress, chains) {
|
|
356
|
+
const params = new URLSearchParams({ address: walletAddress });
|
|
357
|
+
if (chains?.length && chains.length > 0) {
|
|
358
|
+
params.set("chainId", chains[0].toString());
|
|
359
|
+
}
|
|
360
|
+
return this.request(`/api/v1/assets?${params}`, { method: "GET" });
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Get portfolio summary
|
|
364
|
+
*/
|
|
365
|
+
async getPortfolioSummary(walletAddress) {
|
|
366
|
+
const params = new URLSearchParams({ address: walletAddress });
|
|
367
|
+
return this.request(`/api/v1/assets/portfolio?${params}`, { method: "GET" });
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Get user's wallets
|
|
371
|
+
*/
|
|
372
|
+
async getUserWallets(chainId) {
|
|
373
|
+
const params = chainId ? `?chainId=${chainId}` : "";
|
|
374
|
+
return this.request(`/api/v1/wallet${params}`, { method: "GET" });
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Create a new wallet
|
|
378
|
+
*/
|
|
379
|
+
async createWallet(chainId = 8453, type = "smart") {
|
|
380
|
+
return this.request("/api/v1/wallet", {
|
|
381
|
+
method: "POST",
|
|
382
|
+
body: JSON.stringify({ chainId, type })
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Get wallet transactions (placeholder - needs endpoint)
|
|
387
|
+
*/
|
|
388
|
+
async getWalletTransactions(walletAddress, options) {
|
|
389
|
+
const params = new URLSearchParams({ address: walletAddress });
|
|
390
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
391
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
392
|
+
if (options?.chainId) params.set("chainId", options.chainId.toString());
|
|
393
|
+
return this.request(`/api/v1/assets/transactions?${params}`, { method: "GET" });
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Send native token or ERC20
|
|
397
|
+
*/
|
|
398
|
+
async sendTransaction(request) {
|
|
399
|
+
return this.request("/api/v1/wallet/send", {
|
|
400
|
+
method: "POST",
|
|
401
|
+
body: JSON.stringify(request)
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Get transaction status
|
|
406
|
+
*/
|
|
407
|
+
async getTransactionStatus(txId) {
|
|
408
|
+
return this.request(`/api/v1/wallet/transaction/${txId}`, { method: "GET" });
|
|
409
|
+
}
|
|
410
|
+
// ===============================
|
|
411
|
+
// ONRAMP ENDPOINTS (Fiat-to-Crypto)
|
|
412
|
+
// ===============================
|
|
413
|
+
/**
|
|
414
|
+
* Get onramp quote
|
|
415
|
+
*/
|
|
416
|
+
async getOnrampQuote(fiatCurrency, fiatAmount, cryptoCurrency, paymentMethod) {
|
|
417
|
+
const params = new URLSearchParams({
|
|
418
|
+
fiatCurrency,
|
|
419
|
+
fiatAmount: fiatAmount.toString(),
|
|
420
|
+
cryptoCurrency
|
|
421
|
+
});
|
|
422
|
+
if (paymentMethod) params.set("paymentMethod", paymentMethod);
|
|
423
|
+
return this.request(`/api/v1/fiat/onramp/quote?${params}`, { method: "GET" });
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Create onramp session (returns widget URL)
|
|
427
|
+
*/
|
|
428
|
+
async createOnrampSession(request) {
|
|
429
|
+
return this.request("/api/v1/fiat/onramp", {
|
|
430
|
+
method: "POST",
|
|
431
|
+
body: JSON.stringify({
|
|
432
|
+
fiatCurrency: request.fiatCurrency || "USD",
|
|
433
|
+
fiatAmount: request.fiatAmount || 100,
|
|
434
|
+
cryptoCurrency: request.cryptoCurrency || "ETH",
|
|
435
|
+
walletAddress: request.walletAddress,
|
|
436
|
+
chainId: 8453
|
|
437
|
+
// Default to Base
|
|
438
|
+
})
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Get onramp session status
|
|
443
|
+
*/
|
|
444
|
+
async getOnrampStatus(sessionId) {
|
|
445
|
+
return this.request(`/api/v1/fiat/onramp/${sessionId}`, { method: "GET" });
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Get supported currencies (fiat + crypto)
|
|
449
|
+
*/
|
|
450
|
+
async getSupportedCurrencies() {
|
|
451
|
+
return this.request("/api/v1/fiat/onramp", { method: "GET" });
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Get supported fiat currencies
|
|
455
|
+
*/
|
|
456
|
+
async getSupportedFiatCurrencies() {
|
|
457
|
+
const result = await this.getSupportedCurrencies();
|
|
458
|
+
if (result.success && result.data) {
|
|
459
|
+
return { success: true, data: result.data.fiatCurrencies };
|
|
460
|
+
}
|
|
461
|
+
return { success: false, error: result.error };
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Get supported payment methods
|
|
465
|
+
*/
|
|
466
|
+
async getSupportedPaymentMethods(country) {
|
|
467
|
+
return { success: true, data: ["card", "bank_transfer", "apple_pay", "google_pay"] };
|
|
468
|
+
}
|
|
469
|
+
// ===============================
|
|
470
|
+
// SWAP ENDPOINTS
|
|
471
|
+
// ===============================
|
|
472
|
+
/**
|
|
473
|
+
* Get swap quote
|
|
474
|
+
*/
|
|
475
|
+
async getSwapQuote(request) {
|
|
476
|
+
return this.request("/api/v1/swap/quote", {
|
|
477
|
+
method: "POST",
|
|
478
|
+
body: JSON.stringify(request)
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Execute swap
|
|
483
|
+
*/
|
|
484
|
+
async executeSwap(request) {
|
|
485
|
+
return this.request("/api/v1/swap/execute", {
|
|
486
|
+
method: "POST",
|
|
487
|
+
body: JSON.stringify(request)
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Get swap status
|
|
492
|
+
*/
|
|
493
|
+
async getSwapStatus(swapId) {
|
|
494
|
+
return this.request(`/api/v1/swap/${swapId}`, { method: "GET" });
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get supported tokens for swap
|
|
498
|
+
*/
|
|
499
|
+
async getSupportedSwapTokens(chainId) {
|
|
500
|
+
const params = chainId ? `?chainId=${chainId}` : "";
|
|
501
|
+
return this.request(`/api/v1/swap/tokens${params}`, { method: "GET" });
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Get supported chains for swap
|
|
505
|
+
*/
|
|
506
|
+
async getSupportedSwapChains() {
|
|
507
|
+
return this.request("/api/v1/swap/chains", { method: "GET" });
|
|
508
|
+
}
|
|
509
|
+
// ===============================
|
|
510
|
+
// AI TRADING/QUANT ENDPOINTS
|
|
511
|
+
// ===============================
|
|
512
|
+
/**
|
|
513
|
+
* Get available AI trading strategies
|
|
514
|
+
*/
|
|
515
|
+
async getStrategies() {
|
|
516
|
+
return this.request("/api/v1/quant/strategies", { method: "GET" });
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Get strategy details
|
|
520
|
+
*/
|
|
521
|
+
async getStrategy(strategyId) {
|
|
522
|
+
return this.request(`/api/v1/quant/strategies/${strategyId}`, { method: "GET" });
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Get user's positions
|
|
526
|
+
*/
|
|
527
|
+
async getPositions() {
|
|
528
|
+
return this.request("/api/v1/quant/positions", { method: "GET" });
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Create investment order
|
|
532
|
+
*/
|
|
533
|
+
async createOrder(strategyId, amount, currency) {
|
|
534
|
+
return this.request("/api/v1/trading/orders", {
|
|
535
|
+
method: "POST",
|
|
536
|
+
body: JSON.stringify({ strategyId, amount, currency })
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Get user's orders
|
|
541
|
+
*/
|
|
542
|
+
async getUserOrders() {
|
|
543
|
+
return this.request("/api/v1/trading/orders", { method: "GET" });
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Get user's portfolio stats from positions
|
|
547
|
+
*/
|
|
548
|
+
async getPortfolioStats() {
|
|
549
|
+
const positionsResult = await this.getPositions();
|
|
550
|
+
if (positionsResult.success && positionsResult.data) {
|
|
551
|
+
const positions = positionsResult.data;
|
|
552
|
+
const totalInvested = positions.reduce((sum, p) => sum + (p.investedAmount || 0), 0);
|
|
553
|
+
const totalValue = positions.reduce((sum, p) => sum + (p.currentValue || 0), 0);
|
|
554
|
+
const totalPnl = totalValue - totalInvested;
|
|
555
|
+
const totalPnlPercent = totalInvested > 0 ? totalPnl / totalInvested * 100 : 0;
|
|
556
|
+
return {
|
|
557
|
+
success: true,
|
|
558
|
+
data: {
|
|
559
|
+
totalInvested,
|
|
560
|
+
totalValue,
|
|
561
|
+
totalPnl,
|
|
562
|
+
totalPnlPercent,
|
|
563
|
+
activePositions: positions.filter((p) => p.status === "active").length
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
success: true,
|
|
569
|
+
data: { totalInvested: 0, totalValue: 0, totalPnl: 0, totalPnlPercent: 0, activePositions: 0 }
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
// ===============================
|
|
573
|
+
// MARKET/PRICE ENDPOINTS
|
|
574
|
+
// ===============================
|
|
575
|
+
/**
|
|
576
|
+
* Get token prices
|
|
577
|
+
*/
|
|
578
|
+
async getTokenPrices(symbols) {
|
|
579
|
+
const bybitSymbols = symbols.map((s) => {
|
|
580
|
+
const upper = s.toUpperCase();
|
|
581
|
+
if (upper.endsWith("USDT")) return upper;
|
|
582
|
+
return `${upper}USDT`;
|
|
583
|
+
});
|
|
584
|
+
const result = await this.request(
|
|
585
|
+
`/api/v1/trading/market?symbols=${bybitSymbols.join(",")}`,
|
|
586
|
+
{ method: "GET" }
|
|
587
|
+
);
|
|
588
|
+
if (result.success && result.data?.markets) {
|
|
589
|
+
const prices = {};
|
|
590
|
+
for (const market of result.data.markets) {
|
|
591
|
+
const symbol = market.symbol?.replace("USDT", "") || "";
|
|
592
|
+
prices[symbol] = {
|
|
593
|
+
price: parseFloat(market.lastPrice) || 0,
|
|
594
|
+
change24h: parseFloat(market.price24hPcnt) * 100 || 0,
|
|
595
|
+
marketCap: void 0
|
|
596
|
+
// Bybit doesn't provide this
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
return { success: true, data: prices };
|
|
600
|
+
}
|
|
601
|
+
return { success: false, error: result.error };
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Get market data overview
|
|
605
|
+
*/
|
|
606
|
+
async getMarketData() {
|
|
607
|
+
const result = await this.request("/api/v1/trading/market", { method: "GET" });
|
|
608
|
+
if (result.success && result.data?.markets) {
|
|
609
|
+
return {
|
|
610
|
+
success: true,
|
|
611
|
+
data: {
|
|
612
|
+
totalMarketCap: 0,
|
|
613
|
+
// Would need separate API
|
|
614
|
+
totalVolume24h: result.data.markets.reduce((sum, m) => sum + (parseFloat(m.volume24h) || 0), 0),
|
|
615
|
+
btcDominance: 0,
|
|
616
|
+
// Would need separate API
|
|
617
|
+
markets: result.data.markets
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
return { success: false, error: result.error };
|
|
622
|
+
}
|
|
623
|
+
// ===============================
|
|
624
|
+
// NFT ENDPOINTS
|
|
625
|
+
// ===============================
|
|
626
|
+
/**
|
|
627
|
+
* Get user's NFTs
|
|
628
|
+
*/
|
|
629
|
+
async getUserNFTs(walletAddress, options) {
|
|
630
|
+
const params = new URLSearchParams({ address: walletAddress });
|
|
631
|
+
if (options?.chainId) params.set("chainId", options.chainId.toString());
|
|
632
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
633
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
634
|
+
return this.request(`/api/v1/assets/nfts?${params}`, { method: "GET" });
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Get NFT details
|
|
638
|
+
*/
|
|
639
|
+
async getNFTDetails(contractAddress, tokenId, chainId) {
|
|
640
|
+
return this.request(`/api/v1/assets/nfts/${contractAddress}/${tokenId}?chainId=${chainId}`, { method: "GET" });
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Get NFT collection
|
|
644
|
+
*/
|
|
645
|
+
async getNFTCollection(contractAddress, chainId) {
|
|
646
|
+
return this.request(`/api/v1/assets/nfts/collection/${contractAddress}?chainId=${chainId}`, { method: "GET" });
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Transfer NFT
|
|
650
|
+
*/
|
|
651
|
+
async transferNFT(params) {
|
|
652
|
+
return this.request("/api/v1/assets/nfts/transfer", {
|
|
653
|
+
method: "POST",
|
|
654
|
+
body: JSON.stringify(params)
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
// ===============================
|
|
658
|
+
// CONTRACT ENDPOINTS
|
|
659
|
+
// ===============================
|
|
660
|
+
/**
|
|
661
|
+
* Get user's contracts
|
|
662
|
+
*/
|
|
663
|
+
async getUserContracts(options) {
|
|
664
|
+
const params = new URLSearchParams();
|
|
665
|
+
if (options?.chainId) params.set("chainId", options.chainId.toString());
|
|
666
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
667
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
668
|
+
return this.request(`/api/v1/contracts?${params}`, { method: "GET" });
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Get contract details
|
|
672
|
+
*/
|
|
673
|
+
async getContractDetails(address, chainId) {
|
|
674
|
+
return this.request(`/api/v1/contracts/${address}?chainId=${chainId}`, { method: "GET" });
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Read contract (call view function)
|
|
678
|
+
*/
|
|
679
|
+
async readContract(params) {
|
|
680
|
+
return this.request("/api/v1/contracts/read", {
|
|
681
|
+
method: "POST",
|
|
682
|
+
body: JSON.stringify(params)
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Write to contract (execute transaction)
|
|
687
|
+
*/
|
|
688
|
+
async writeContract(params) {
|
|
689
|
+
return this.request("/api/v1/contracts/write", {
|
|
690
|
+
method: "POST",
|
|
691
|
+
body: JSON.stringify(params)
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Deploy contract
|
|
696
|
+
*/
|
|
697
|
+
async deployContract(params) {
|
|
698
|
+
return this.request("/api/v1/contracts/deploy", {
|
|
699
|
+
method: "POST",
|
|
700
|
+
body: JSON.stringify(params)
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
// ===============================
|
|
704
|
+
// OFFRAMP ENDPOINTS (Crypto-to-Fiat)
|
|
705
|
+
// ===============================
|
|
706
|
+
/**
|
|
707
|
+
* Get offramp quote
|
|
708
|
+
*/
|
|
709
|
+
async getOfframpQuote(cryptoCurrency, cryptoAmount, fiatCurrency, payoutMethod) {
|
|
710
|
+
const params = new URLSearchParams({
|
|
711
|
+
cryptoCurrency,
|
|
712
|
+
cryptoAmount: cryptoAmount.toString(),
|
|
713
|
+
fiatCurrency
|
|
714
|
+
});
|
|
715
|
+
if (payoutMethod) params.set("payoutMethod", payoutMethod);
|
|
716
|
+
return this.request(`/api/v1/fiat/offramp/quote?${params}`, { method: "GET" });
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Create offramp transaction
|
|
720
|
+
*/
|
|
721
|
+
async createOfframpTransaction(request) {
|
|
722
|
+
return this.request("/api/v1/fiat/offramp", {
|
|
723
|
+
method: "POST",
|
|
724
|
+
body: JSON.stringify(request)
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Get offramp transaction status
|
|
729
|
+
*/
|
|
730
|
+
async getOfframpStatus(transactionId) {
|
|
731
|
+
return this.request(`/api/v1/fiat/offramp/${transactionId}`, { method: "GET" });
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Get supported payout methods
|
|
735
|
+
*/
|
|
736
|
+
async getSupportedPayoutMethods(country) {
|
|
737
|
+
const params = country ? `?country=${country}` : "";
|
|
738
|
+
return this.request(`/api/v1/fiat/offramp/methods${params}`, { method: "GET" });
|
|
739
|
+
}
|
|
740
|
+
// ===============================
|
|
741
|
+
// BILL PAYMENT ENDPOINTS
|
|
742
|
+
// ===============================
|
|
743
|
+
/**
|
|
744
|
+
* Get bill providers
|
|
745
|
+
*/
|
|
746
|
+
async getBillProviders(country, category) {
|
|
747
|
+
const params = new URLSearchParams();
|
|
748
|
+
if (country) params.set("country", country);
|
|
749
|
+
if (category) params.set("category", category);
|
|
750
|
+
return this.request(`/api/v1/bills/providers?${params}`, { method: "GET" });
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Get bill details/validate account
|
|
754
|
+
*/
|
|
755
|
+
async validateBillAccount(providerId, accountNumber) {
|
|
756
|
+
return this.request("/api/v1/bills/validate", {
|
|
757
|
+
method: "POST",
|
|
758
|
+
body: JSON.stringify({ providerId, accountNumber })
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Pay bill
|
|
763
|
+
*/
|
|
764
|
+
async payBill(params) {
|
|
765
|
+
return this.request("/api/v1/bills/pay", {
|
|
766
|
+
method: "POST",
|
|
767
|
+
body: JSON.stringify(params)
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Get bill payment history
|
|
772
|
+
*/
|
|
773
|
+
async getBillHistory(options) {
|
|
774
|
+
const params = new URLSearchParams();
|
|
775
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
776
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
777
|
+
return this.request(`/api/v1/bills/history?${params}`, { method: "GET" });
|
|
778
|
+
}
|
|
779
|
+
// ===============================
|
|
780
|
+
// STAKING ENDPOINTS
|
|
781
|
+
// ===============================
|
|
782
|
+
/**
|
|
783
|
+
* Get staking pools
|
|
784
|
+
*/
|
|
785
|
+
async getStakingPools(chainId) {
|
|
786
|
+
const params = chainId ? `?chainId=${chainId}` : "";
|
|
787
|
+
return this.request(`/api/v1/staking/pools${params}`, { method: "GET" });
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Get user's staking positions
|
|
791
|
+
*/
|
|
792
|
+
async getStakingPositions() {
|
|
793
|
+
return this.request("/api/v1/staking/positions", { method: "GET" });
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Stake tokens
|
|
797
|
+
*/
|
|
798
|
+
async stake(params) {
|
|
799
|
+
return this.request("/api/v1/staking/stake", {
|
|
800
|
+
method: "POST",
|
|
801
|
+
body: JSON.stringify(params)
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Unstake tokens
|
|
806
|
+
*/
|
|
807
|
+
async unstake(params) {
|
|
808
|
+
return this.request("/api/v1/staking/unstake", {
|
|
809
|
+
method: "POST",
|
|
810
|
+
body: JSON.stringify(params)
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Claim staking rewards
|
|
815
|
+
*/
|
|
816
|
+
async claimStakingRewards(positionId) {
|
|
817
|
+
return this.request("/api/v1/staking/claim", {
|
|
818
|
+
method: "POST",
|
|
819
|
+
body: JSON.stringify({ positionId })
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
// ===============================
|
|
823
|
+
// USER PROFILE ENDPOINTS
|
|
824
|
+
// ===============================
|
|
825
|
+
/**
|
|
826
|
+
* Get user profile
|
|
827
|
+
*/
|
|
828
|
+
async getUserProfile() {
|
|
829
|
+
return this.request("/api/v1/user/profile", { method: "GET" });
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Update user profile
|
|
833
|
+
*/
|
|
834
|
+
async updateUserProfile(updates) {
|
|
835
|
+
return this.request("/api/v1/user/profile", {
|
|
836
|
+
method: "PATCH",
|
|
837
|
+
body: JSON.stringify(updates)
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Get user settings
|
|
842
|
+
*/
|
|
843
|
+
async getUserSettings() {
|
|
844
|
+
return this.request("/api/v1/user/settings", { method: "GET" });
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Update user settings
|
|
848
|
+
*/
|
|
849
|
+
async updateUserSettings(updates) {
|
|
850
|
+
return this.request("/api/v1/user/settings", {
|
|
851
|
+
method: "PATCH",
|
|
852
|
+
body: JSON.stringify(updates)
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
// ===============================
|
|
856
|
+
// NOTIFICATION ENDPOINTS
|
|
857
|
+
// ===============================
|
|
858
|
+
/**
|
|
859
|
+
* Get notifications
|
|
860
|
+
*/
|
|
861
|
+
async getNotifications(options) {
|
|
862
|
+
const params = new URLSearchParams();
|
|
863
|
+
if (options?.unreadOnly) params.set("unreadOnly", "true");
|
|
864
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
865
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
866
|
+
return this.request(`/api/v1/notifications?${params}`, { method: "GET" });
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Mark notification as read
|
|
870
|
+
*/
|
|
871
|
+
async markNotificationRead(notificationId) {
|
|
872
|
+
return this.request(`/api/v1/notifications/${notificationId}/read`, { method: "POST" });
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Mark all notifications as read
|
|
876
|
+
*/
|
|
877
|
+
async markAllNotificationsRead() {
|
|
878
|
+
return this.request("/api/v1/notifications/read-all", { method: "POST" });
|
|
879
|
+
}
|
|
880
|
+
// ===============================
|
|
881
|
+
// REFERRAL ENDPOINTS
|
|
882
|
+
// ===============================
|
|
883
|
+
/**
|
|
884
|
+
* Get referral info
|
|
885
|
+
*/
|
|
886
|
+
async getReferralInfo() {
|
|
887
|
+
return this.request("/api/v1/referral", { method: "GET" });
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Get referred users
|
|
891
|
+
*/
|
|
892
|
+
async getReferrals() {
|
|
893
|
+
return this.request("/api/v1/referral/list", { method: "GET" });
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Apply referral code
|
|
897
|
+
*/
|
|
898
|
+
async applyReferralCode(code) {
|
|
899
|
+
return this.request("/api/v1/referral/apply", {
|
|
900
|
+
method: "POST",
|
|
901
|
+
body: JSON.stringify({ code })
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Claim referral rewards
|
|
906
|
+
*/
|
|
907
|
+
async claimReferralRewards() {
|
|
908
|
+
return this.request("/api/v1/referral/claim", { method: "POST" });
|
|
909
|
+
}
|
|
910
|
+
// ===============================
|
|
911
|
+
// KYC ENDPOINTS
|
|
912
|
+
// ===============================
|
|
913
|
+
/**
|
|
914
|
+
* Get KYC status
|
|
915
|
+
*/
|
|
916
|
+
async getKycStatus() {
|
|
917
|
+
return this.request("/api/v1/kyc/status", { method: "GET" });
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Start KYC verification
|
|
921
|
+
*/
|
|
922
|
+
async startKycVerification(level) {
|
|
923
|
+
return this.request("/api/v1/kyc/start", {
|
|
924
|
+
method: "POST",
|
|
925
|
+
body: JSON.stringify({ level })
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Submit KYC documents
|
|
930
|
+
*/
|
|
931
|
+
async submitKycDocuments(params) {
|
|
932
|
+
return this.request("/api/v1/kyc/submit", {
|
|
933
|
+
method: "POST",
|
|
934
|
+
body: JSON.stringify(params)
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
// ===============================
|
|
938
|
+
// BRIDGE ENDPOINTS
|
|
939
|
+
// ===============================
|
|
940
|
+
/**
|
|
941
|
+
* Get bridge quote
|
|
942
|
+
*/
|
|
943
|
+
async getBridgeQuote(params) {
|
|
944
|
+
return this.request("/api/v1/bridge/quote", {
|
|
945
|
+
method: "POST",
|
|
946
|
+
body: JSON.stringify(params)
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Execute bridge transaction
|
|
951
|
+
*/
|
|
952
|
+
async executeBridge(params) {
|
|
953
|
+
return this.request("/api/v1/bridge/execute", {
|
|
954
|
+
method: "POST",
|
|
955
|
+
body: JSON.stringify(params)
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Get bridge transaction status
|
|
960
|
+
*/
|
|
961
|
+
async getBridgeStatus(bridgeId) {
|
|
962
|
+
return this.request(`/api/v1/bridge/${bridgeId}`, { method: "GET" });
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Get supported bridge routes
|
|
966
|
+
*/
|
|
967
|
+
async getSupportedBridgeRoutes() {
|
|
968
|
+
return this.request("/api/v1/bridge/routes", { method: "GET" });
|
|
969
|
+
}
|
|
970
|
+
// ===============================
|
|
971
|
+
// GAS ENDPOINTS
|
|
972
|
+
// ===============================
|
|
973
|
+
/**
|
|
974
|
+
* Get gas estimate for transaction
|
|
975
|
+
*/
|
|
976
|
+
async getGasEstimate(params) {
|
|
977
|
+
return this.request("/api/v1/gas/estimate", {
|
|
978
|
+
method: "POST",
|
|
979
|
+
body: JSON.stringify(params)
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Get current gas prices for chain
|
|
984
|
+
*/
|
|
985
|
+
async getGasPrice(chainId) {
|
|
986
|
+
return this.request(`/api/v1/gas/price?chainId=${chainId}`, { method: "GET" });
|
|
987
|
+
}
|
|
988
|
+
// ===============================
|
|
989
|
+
// WALLET IMPORT/EXPORT ENDPOINTS
|
|
990
|
+
// ===============================
|
|
991
|
+
/**
|
|
992
|
+
* Import wallet from private key or mnemonic
|
|
993
|
+
*/
|
|
994
|
+
async importWallet(request) {
|
|
995
|
+
return this.request("/api/v1/wallet/import", {
|
|
996
|
+
method: "POST",
|
|
997
|
+
body: JSON.stringify(request)
|
|
998
|
+
}, true);
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Export wallet (get encrypted private key)
|
|
1002
|
+
* Requires additional authentication
|
|
1003
|
+
*/
|
|
1004
|
+
async exportWallet(walletId, pin) {
|
|
1005
|
+
return this.request("/api/v1/wallet/export", {
|
|
1006
|
+
method: "POST",
|
|
1007
|
+
body: JSON.stringify({ walletId, pin })
|
|
1008
|
+
}, true);
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Generate new mnemonic phrase
|
|
1012
|
+
*/
|
|
1013
|
+
async generateMnemonic() {
|
|
1014
|
+
return this.request("/api/v1/wallet/generate-mnemonic", { method: "POST" }, true);
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Validate mnemonic phrase
|
|
1018
|
+
*/
|
|
1019
|
+
async validateMnemonic(mnemonic) {
|
|
1020
|
+
return this.request("/api/v1/wallet/validate-mnemonic", {
|
|
1021
|
+
method: "POST",
|
|
1022
|
+
body: JSON.stringify({ mnemonic })
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
// ===============================
|
|
1026
|
+
// PORTFOLIO ANALYTICS ENDPOINTS
|
|
1027
|
+
// ===============================
|
|
1028
|
+
/**
|
|
1029
|
+
* Get portfolio analytics with historical data
|
|
1030
|
+
*/
|
|
1031
|
+
async getPortfolioAnalytics(walletAddress, period = "30d") {
|
|
1032
|
+
const params = new URLSearchParams({ address: walletAddress, period });
|
|
1033
|
+
return this.request(`/api/v1/analytics/portfolio?${params}`, { method: "GET" });
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Get transaction analytics
|
|
1037
|
+
*/
|
|
1038
|
+
async getTransactionAnalytics(walletAddress, period = "30d") {
|
|
1039
|
+
const params = new URLSearchParams({ address: walletAddress, period });
|
|
1040
|
+
return this.request(`/api/v1/analytics/transactions?${params}`, { method: "GET" });
|
|
1041
|
+
}
|
|
1042
|
+
// ===============================
|
|
1043
|
+
// ADVANCED TRADING ENDPOINTS
|
|
1044
|
+
// ===============================
|
|
1045
|
+
/**
|
|
1046
|
+
* Create limit order
|
|
1047
|
+
*/
|
|
1048
|
+
async createLimitOrder(params) {
|
|
1049
|
+
return this.request("/api/v1/trading/limit-orders", {
|
|
1050
|
+
method: "POST",
|
|
1051
|
+
body: JSON.stringify(params)
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Get user's limit orders
|
|
1056
|
+
*/
|
|
1057
|
+
async getLimitOrders(status) {
|
|
1058
|
+
const params = status ? `?status=${status}` : "";
|
|
1059
|
+
return this.request(`/api/v1/trading/limit-orders${params}`, { method: "GET" });
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Cancel limit order
|
|
1063
|
+
*/
|
|
1064
|
+
async cancelLimitOrder(orderId) {
|
|
1065
|
+
return this.request(`/api/v1/trading/limit-orders/${orderId}`, { method: "DELETE" });
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Set price alert
|
|
1069
|
+
*/
|
|
1070
|
+
async setPriceAlert(params) {
|
|
1071
|
+
return this.request("/api/v1/trading/alerts", {
|
|
1072
|
+
method: "POST",
|
|
1073
|
+
body: JSON.stringify(params)
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Get price alerts
|
|
1078
|
+
*/
|
|
1079
|
+
async getPriceAlerts() {
|
|
1080
|
+
return this.request("/api/v1/trading/alerts", { method: "GET" });
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Delete price alert
|
|
1084
|
+
*/
|
|
1085
|
+
async deletePriceAlert(alertId) {
|
|
1086
|
+
return this.request(`/api/v1/trading/alerts/${alertId}`, { method: "DELETE" });
|
|
1087
|
+
}
|
|
1088
|
+
// ===============================
|
|
1089
|
+
// SESSION MANAGEMENT
|
|
1090
|
+
// ===============================
|
|
1091
|
+
/**
|
|
1092
|
+
* Get active sessions
|
|
1093
|
+
*/
|
|
1094
|
+
async getActiveSessions() {
|
|
1095
|
+
return this.request("/api/v1/auth/sessions", { method: "GET" });
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Revoke session
|
|
1099
|
+
*/
|
|
1100
|
+
async revokeSession(sessionId) {
|
|
1101
|
+
return this.request(`/api/v1/auth/sessions/${sessionId}`, { method: "DELETE" });
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Revoke all other sessions
|
|
1105
|
+
*/
|
|
1106
|
+
async revokeAllOtherSessions() {
|
|
1107
|
+
return this.request("/api/v1/auth/sessions/revoke-all", { method: "POST" });
|
|
1108
|
+
}
|
|
1109
|
+
// ========== Webhooks ==========
|
|
1110
|
+
/**
|
|
1111
|
+
* List webhooks for the project
|
|
1112
|
+
*/
|
|
1113
|
+
async listWebhooks(options) {
|
|
1114
|
+
const params = new URLSearchParams();
|
|
1115
|
+
if (options?.isActive !== void 0) params.set("isActive", String(options.isActive));
|
|
1116
|
+
const query = params.toString();
|
|
1117
|
+
return this.request(`/api/v1/webhooks${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Get webhook by ID
|
|
1121
|
+
*/
|
|
1122
|
+
async getWebhook(webhookId) {
|
|
1123
|
+
return this.request(`/api/v1/webhooks/${webhookId}`, { method: "GET" });
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Create a webhook
|
|
1127
|
+
*/
|
|
1128
|
+
async createWebhook(input) {
|
|
1129
|
+
return this.request("/api/v1/webhooks", {
|
|
1130
|
+
method: "POST",
|
|
1131
|
+
body: JSON.stringify(input)
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Update a webhook
|
|
1136
|
+
*/
|
|
1137
|
+
async updateWebhook(webhookId, input) {
|
|
1138
|
+
return this.request(`/api/v1/webhooks/${webhookId}`, {
|
|
1139
|
+
method: "PATCH",
|
|
1140
|
+
body: JSON.stringify(input)
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Delete a webhook
|
|
1145
|
+
*/
|
|
1146
|
+
async deleteWebhook(webhookId) {
|
|
1147
|
+
return this.request(`/api/v1/webhooks/${webhookId}`, { method: "DELETE" });
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* Get webhook deliveries
|
|
1151
|
+
*/
|
|
1152
|
+
async getWebhookDeliveries(webhookId, options) {
|
|
1153
|
+
const params = new URLSearchParams();
|
|
1154
|
+
if (options?.status) params.set("status", options.status);
|
|
1155
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
1156
|
+
if (options?.offset) params.set("offset", String(options.offset));
|
|
1157
|
+
const query = params.toString();
|
|
1158
|
+
return this.request(`/api/v1/webhooks/${webhookId}/deliveries${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Test a webhook
|
|
1162
|
+
*/
|
|
1163
|
+
async testWebhook(webhookId) {
|
|
1164
|
+
return this.request(`/api/v1/webhooks/${webhookId}/test`, { method: "POST" });
|
|
1165
|
+
}
|
|
1166
|
+
// ========== Admin (requires admin role) ==========
|
|
1167
|
+
/**
|
|
1168
|
+
* List all users (admin only)
|
|
1169
|
+
*/
|
|
1170
|
+
async adminListUsers(options) {
|
|
1171
|
+
const params = new URLSearchParams();
|
|
1172
|
+
if (options?.page) params.set("page", String(options.page));
|
|
1173
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
1174
|
+
if (options?.search) params.set("search", options.search);
|
|
1175
|
+
if (options?.sortBy) params.set("sortBy", options.sortBy);
|
|
1176
|
+
if (options?.sortOrder) params.set("sortOrder", options.sortOrder);
|
|
1177
|
+
if (options?.role) params.set("role", options.role);
|
|
1178
|
+
if (options?.kycStatus) params.set("kycStatus", options.kycStatus);
|
|
1179
|
+
if (options?.isActive !== void 0) params.set("isActive", String(options.isActive));
|
|
1180
|
+
const query = params.toString();
|
|
1181
|
+
return this.request(`/api/v1/admin/users${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Get user by ID (admin only)
|
|
1185
|
+
*/
|
|
1186
|
+
async adminGetUser(userId) {
|
|
1187
|
+
return this.request(`/api/v1/admin/users/${userId}`, { method: "GET" });
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Update user (admin only)
|
|
1191
|
+
*/
|
|
1192
|
+
async adminUpdateUser(userId, data) {
|
|
1193
|
+
return this.request(`/api/v1/admin/users/${userId}`, {
|
|
1194
|
+
method: "PATCH",
|
|
1195
|
+
body: JSON.stringify(data)
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* List all projects (admin only)
|
|
1200
|
+
*/
|
|
1201
|
+
async adminListProjects(options) {
|
|
1202
|
+
const params = new URLSearchParams();
|
|
1203
|
+
if (options?.page) params.set("page", String(options.page));
|
|
1204
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
1205
|
+
if (options?.search) params.set("search", options.search);
|
|
1206
|
+
if (options?.sortBy) params.set("sortBy", options.sortBy);
|
|
1207
|
+
if (options?.sortOrder) params.set("sortOrder", options.sortOrder);
|
|
1208
|
+
if (options?.isActive !== void 0) params.set("isActive", String(options.isActive));
|
|
1209
|
+
const query = params.toString();
|
|
1210
|
+
return this.request(`/api/v1/admin/projects${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Get project by ID (admin only)
|
|
1214
|
+
*/
|
|
1215
|
+
async adminGetProject(projectId) {
|
|
1216
|
+
return this.request(`/api/v1/admin/projects/${projectId}`, { method: "GET" });
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Update project (admin only)
|
|
1220
|
+
*/
|
|
1221
|
+
async adminUpdateProject(projectId, data) {
|
|
1222
|
+
return this.request(`/api/v1/admin/projects/${projectId}`, {
|
|
1223
|
+
method: "PATCH",
|
|
1224
|
+
body: JSON.stringify(data)
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Regenerate project API key (admin only)
|
|
1229
|
+
*/
|
|
1230
|
+
async adminRegenerateApiKey(projectId) {
|
|
1231
|
+
return this.request(`/api/v1/admin/projects/${projectId}/regenerate-key`, { method: "POST" });
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Get system statistics (admin only)
|
|
1235
|
+
*/
|
|
1236
|
+
async adminGetStats(days) {
|
|
1237
|
+
const query = days ? `?days=${days}` : "";
|
|
1238
|
+
return this.request(`/api/v1/admin/stats${query}`, { method: "GET" });
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Get system logs (admin only)
|
|
1242
|
+
*/
|
|
1243
|
+
async adminGetLogs(options) {
|
|
1244
|
+
const params = new URLSearchParams();
|
|
1245
|
+
if (options?.level) params.set("level", options.level);
|
|
1246
|
+
if (options?.service) params.set("service", options.service);
|
|
1247
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
1248
|
+
if (options?.offset) params.set("offset", String(options.offset));
|
|
1249
|
+
if (options?.startDate) params.set("startDate", options.startDate);
|
|
1250
|
+
if (options?.endDate) params.set("endDate", options.endDate);
|
|
1251
|
+
const query = params.toString();
|
|
1252
|
+
return this.request(`/api/v1/admin/logs${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Get rate limit status (admin only)
|
|
1256
|
+
*/
|
|
1257
|
+
async adminGetRateLimits(options) {
|
|
1258
|
+
const params = new URLSearchParams();
|
|
1259
|
+
if (options?.identifier) params.set("identifier", options.identifier);
|
|
1260
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
1261
|
+
const query = params.toString();
|
|
1262
|
+
return this.request(`/api/v1/admin/rate-limits${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Clear rate limits for an identifier (admin only)
|
|
1266
|
+
*/
|
|
1267
|
+
async adminClearRateLimits(identifier) {
|
|
1268
|
+
return this.request(`/api/v1/admin/rate-limits/${identifier}`, { method: "DELETE" });
|
|
1269
|
+
}
|
|
1270
|
+
// ========== AI Quant Trading ==========
|
|
1271
|
+
/**
|
|
1272
|
+
* Get all AI trading strategies
|
|
1273
|
+
*/
|
|
1274
|
+
async getAIStrategies(filters) {
|
|
1275
|
+
const params = new URLSearchParams();
|
|
1276
|
+
if (filters?.category) params.set("category", filters.category);
|
|
1277
|
+
if (filters?.riskLevel) params.set("risk_level", String(filters.riskLevel));
|
|
1278
|
+
if (filters?.minTvl) params.set("min_tvl", String(filters.minTvl));
|
|
1279
|
+
if (filters?.isActive !== void 0) params.set("is_active", String(filters.isActive));
|
|
1280
|
+
const query = params.toString();
|
|
1281
|
+
return this.request(`/api/v1/ai-quant/strategies${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Get AI strategy details
|
|
1285
|
+
*/
|
|
1286
|
+
async getAIStrategy(strategyId, include) {
|
|
1287
|
+
const params = new URLSearchParams();
|
|
1288
|
+
if (include?.length) params.set("include", include.join(","));
|
|
1289
|
+
const query = params.toString();
|
|
1290
|
+
return this.request(`/api/v1/ai-quant/strategies/${strategyId}${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Get strategy performance history
|
|
1294
|
+
*/
|
|
1295
|
+
async getAIStrategyPerformance(strategyId, days = 30) {
|
|
1296
|
+
return this.request(`/api/v1/ai-quant/strategies/${strategyId}?include=performance&days=${days}`, { method: "GET" });
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Get real-time market data for strategy pairs
|
|
1300
|
+
*/
|
|
1301
|
+
async getAIStrategyMarketData(strategyId) {
|
|
1302
|
+
return this.request(`/api/v1/ai-quant/strategies/${strategyId}?include=market`, { method: "GET" });
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Create AI trading order
|
|
1306
|
+
*/
|
|
1307
|
+
async createAIOrder(request) {
|
|
1308
|
+
return this.request("/api/v1/ai-quant/orders", {
|
|
1309
|
+
method: "POST",
|
|
1310
|
+
body: JSON.stringify(request)
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Get user's AI orders
|
|
1315
|
+
*/
|
|
1316
|
+
async getAIOrders(filters) {
|
|
1317
|
+
const params = new URLSearchParams();
|
|
1318
|
+
if (filters?.strategyId) params.set("strategy_id", filters.strategyId);
|
|
1319
|
+
if (filters?.status) params.set("status", filters.status);
|
|
1320
|
+
const query = params.toString();
|
|
1321
|
+
return this.request(`/api/v1/ai-quant/orders${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Get AI order details
|
|
1325
|
+
*/
|
|
1326
|
+
async getAIOrder(orderId) {
|
|
1327
|
+
return this.request(`/api/v1/ai-quant/orders/${orderId}`, { method: "GET" });
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Pause AI order
|
|
1331
|
+
*/
|
|
1332
|
+
async pauseAIOrder(orderId) {
|
|
1333
|
+
return this.request(`/api/v1/ai-quant/orders/${orderId}/pause`, { method: "POST" });
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Resume AI order
|
|
1337
|
+
*/
|
|
1338
|
+
async resumeAIOrder(orderId) {
|
|
1339
|
+
return this.request(`/api/v1/ai-quant/orders/${orderId}/resume`, { method: "POST" });
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Request redemption for AI order
|
|
1343
|
+
*/
|
|
1344
|
+
async redeemAIOrder(orderId) {
|
|
1345
|
+
return this.request(`/api/v1/ai-quant/orders/${orderId}/redeem`, { method: "POST" });
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Get AI portfolio summary
|
|
1349
|
+
*/
|
|
1350
|
+
async getAIPortfolio(include) {
|
|
1351
|
+
const params = new URLSearchParams();
|
|
1352
|
+
if (include?.length) params.set("include", include.join(","));
|
|
1353
|
+
const query = params.toString();
|
|
1354
|
+
return this.request(`/api/v1/ai-quant/portfolio${query ? `?${query}` : ""}`, { method: "GET" });
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Get user's trade allocations
|
|
1358
|
+
*/
|
|
1359
|
+
async getAITradeAllocations(limit = 50) {
|
|
1360
|
+
return this.request(`/api/v1/ai-quant/portfolio?include=allocations&limit=${limit}`, { method: "GET" });
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Get trade history for a strategy
|
|
1364
|
+
*/
|
|
1365
|
+
async getAITradeHistory(strategyId, limit = 50) {
|
|
1366
|
+
return this.request(`/api/v1/ai-quant/strategies/${strategyId}?include=trades&limit=${limit}`, { method: "GET" });
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Execute AI signals for a strategy (admin only)
|
|
1370
|
+
*/
|
|
1371
|
+
async executeAISignals(strategyId) {
|
|
1372
|
+
return this.request("/api/v1/ai-quant/execute", {
|
|
1373
|
+
method: "POST",
|
|
1374
|
+
body: JSON.stringify({ strategyId })
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
// ========== Free Price APIs (No API Key Required) ==========
|
|
1378
|
+
/**
|
|
1379
|
+
* Get cryptocurrency prices (FREE - uses CoinGecko/Binance/CoinCap)
|
|
1380
|
+
*/
|
|
1381
|
+
async getCryptoPrices(symbols) {
|
|
1382
|
+
return this.request(`/api/v1/prices?symbols=${symbols.join(",")}`, { method: "GET" });
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Get single cryptocurrency price (FREE)
|
|
1386
|
+
*/
|
|
1387
|
+
async getCryptoPrice(symbol) {
|
|
1388
|
+
return this.request(`/api/v1/prices/${symbol}`, { method: "GET" });
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* Get OHLCV candles for charting (FREE - from Binance)
|
|
1392
|
+
*/
|
|
1393
|
+
async getCryptoCandles(symbol, interval = "1h", limit = 100) {
|
|
1394
|
+
return this.request(`/api/v1/prices/${symbol}?candles=true&interval=${interval}&limit=${limit}`, { method: "GET" });
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Get top cryptocurrencies by market cap (FREE)
|
|
1398
|
+
*/
|
|
1399
|
+
async getTopCryptos(limit = 20) {
|
|
1400
|
+
return this.request(`/api/v1/prices?type=top&limit=${limit}`, { method: "GET" });
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* Get crypto market overview (FREE)
|
|
1404
|
+
*/
|
|
1405
|
+
async getCryptoMarketOverview() {
|
|
1406
|
+
return this.request("/api/v1/prices?type=overview", { method: "GET" });
|
|
1407
|
+
}
|
|
1408
|
+
};
|
|
1409
|
+
function createOneEngineClient(options) {
|
|
1410
|
+
return new OneEngineClient(options);
|
|
1411
|
+
}
|
|
1412
|
+
var supabaseInstance = null;
|
|
1413
|
+
function createSupabaseClient(url, anonKey) {
|
|
1414
|
+
const config2 = getConfig();
|
|
1415
|
+
const supabaseUrl = url || config2.supabaseUrl;
|
|
1416
|
+
const supabaseAnonKey = anonKey || config2.supabaseAnonKey;
|
|
1417
|
+
if (!supabaseUrl || !supabaseAnonKey) {
|
|
1418
|
+
throw new Error("Supabase URL and Anon Key are required");
|
|
1419
|
+
}
|
|
1420
|
+
return createClient(supabaseUrl, supabaseAnonKey, {
|
|
1421
|
+
auth: {
|
|
1422
|
+
autoRefreshToken: true,
|
|
1423
|
+
persistSession: true,
|
|
1424
|
+
detectSessionInUrl: true
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
function getSupabaseClient() {
|
|
1429
|
+
if (!supabaseInstance) {
|
|
1430
|
+
supabaseInstance = createSupabaseClient();
|
|
1431
|
+
}
|
|
1432
|
+
return supabaseInstance;
|
|
1433
|
+
}
|
|
1434
|
+
var SupabaseService = class {
|
|
1435
|
+
constructor(client) {
|
|
1436
|
+
this.client = client || getSupabaseClient();
|
|
1437
|
+
}
|
|
1438
|
+
// ===== Auth Methods =====
|
|
1439
|
+
async signInWithEmail(email) {
|
|
1440
|
+
const { data, error } = await this.client.auth.signInWithOtp({
|
|
1441
|
+
email,
|
|
1442
|
+
options: {
|
|
1443
|
+
shouldCreateUser: true
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
return { data, error };
|
|
1447
|
+
}
|
|
1448
|
+
async verifyOtp(email, token) {
|
|
1449
|
+
const { data, error } = await this.client.auth.verifyOtp({
|
|
1450
|
+
email,
|
|
1451
|
+
token,
|
|
1452
|
+
type: "email"
|
|
1453
|
+
});
|
|
1454
|
+
return { data, error };
|
|
1455
|
+
}
|
|
1456
|
+
async signOut() {
|
|
1457
|
+
const { error } = await this.client.auth.signOut();
|
|
1458
|
+
return { error };
|
|
1459
|
+
}
|
|
1460
|
+
async getSession() {
|
|
1461
|
+
const { data, error } = await this.client.auth.getSession();
|
|
1462
|
+
return { session: data.session, error };
|
|
1463
|
+
}
|
|
1464
|
+
async getUser() {
|
|
1465
|
+
const { data, error } = await this.client.auth.getUser();
|
|
1466
|
+
return { user: data.user, error };
|
|
1467
|
+
}
|
|
1468
|
+
// ===== User Profile Methods =====
|
|
1469
|
+
async getUserProfile(userId) {
|
|
1470
|
+
const { data, error } = await this.client.from("user_profiles").select("*").eq("user_id", userId).single();
|
|
1471
|
+
return { data, error };
|
|
1472
|
+
}
|
|
1473
|
+
async updateUserProfile(userId, updates) {
|
|
1474
|
+
const { data, error } = await this.client.from("user_profiles").update(updates).eq("user_id", userId).select().single();
|
|
1475
|
+
return { data, error };
|
|
1476
|
+
}
|
|
1477
|
+
// ===== Transaction Methods =====
|
|
1478
|
+
async getTransactions(userId, limit = 50) {
|
|
1479
|
+
const { data, error } = await this.client.from("transactions").select("*").eq("user_id", userId).order("created_at", { ascending: false }).limit(limit);
|
|
1480
|
+
return { data, error };
|
|
1481
|
+
}
|
|
1482
|
+
async createTransaction(transaction) {
|
|
1483
|
+
const { data, error } = await this.client.from("transactions").insert(transaction).select().single();
|
|
1484
|
+
return { data, error };
|
|
1485
|
+
}
|
|
1486
|
+
// ===== AI Trading Methods =====
|
|
1487
|
+
async getStrategies(status = "active") {
|
|
1488
|
+
const { data, error } = await this.client.from("ai_strategies").select("*").eq("status", status).order("total_aum", { ascending: false });
|
|
1489
|
+
return { data, error };
|
|
1490
|
+
}
|
|
1491
|
+
async getStrategyById(strategyId) {
|
|
1492
|
+
const { data, error } = await this.client.from("ai_strategies").select("*").eq("id", strategyId).single();
|
|
1493
|
+
return { data, error };
|
|
1494
|
+
}
|
|
1495
|
+
async getUserOrders(userId) {
|
|
1496
|
+
const { data, error } = await this.client.from("ai_orders").select(`*, ai_strategies (name)`).eq("user_id", userId).order("created_at", { ascending: false });
|
|
1497
|
+
return { data, error };
|
|
1498
|
+
}
|
|
1499
|
+
async createOrder(order) {
|
|
1500
|
+
const { data, error } = await this.client.from("ai_orders").insert(order).select().single();
|
|
1501
|
+
return { data, error };
|
|
1502
|
+
}
|
|
1503
|
+
// ===== Card Methods =====
|
|
1504
|
+
async getUserCards(userId) {
|
|
1505
|
+
const { data, error } = await this.client.from("cards").select("*").eq("user_id", userId).order("created_at", { ascending: false });
|
|
1506
|
+
return { data, error };
|
|
1507
|
+
}
|
|
1508
|
+
// ===== Realtime Subscriptions =====
|
|
1509
|
+
subscribeToTransactions(userId, callback) {
|
|
1510
|
+
return this.client.channel(`transactions:${userId}`).on(
|
|
1511
|
+
"postgres_changes",
|
|
1512
|
+
{
|
|
1513
|
+
event: "*",
|
|
1514
|
+
schema: "public",
|
|
1515
|
+
table: "transactions",
|
|
1516
|
+
filter: `user_id=eq.${userId}`
|
|
1517
|
+
},
|
|
1518
|
+
callback
|
|
1519
|
+
).subscribe();
|
|
1520
|
+
}
|
|
1521
|
+
unsubscribe(channel) {
|
|
1522
|
+
return this.client.removeChannel(channel);
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
|
|
1526
|
+
// src/services/price.ts
|
|
1527
|
+
var COINGECKO_API = "https://api.coingecko.com/api/v3";
|
|
1528
|
+
var FALLBACK_PRICES = {
|
|
1529
|
+
ETH: 3500,
|
|
1530
|
+
BTC: 95e3,
|
|
1531
|
+
BNB: 700,
|
|
1532
|
+
MATIC: 0.5,
|
|
1533
|
+
AVAX: 40,
|
|
1534
|
+
USDT: 1,
|
|
1535
|
+
USDC: 1,
|
|
1536
|
+
DAI: 1,
|
|
1537
|
+
WBTC: 95e3,
|
|
1538
|
+
WETH: 3500,
|
|
1539
|
+
ARB: 1.2,
|
|
1540
|
+
OP: 2.5,
|
|
1541
|
+
LINK: 20,
|
|
1542
|
+
UNI: 12,
|
|
1543
|
+
AAVE: 250,
|
|
1544
|
+
SOL: 200
|
|
1545
|
+
};
|
|
1546
|
+
var PriceService = class {
|
|
1547
|
+
constructor() {
|
|
1548
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
1549
|
+
this.cacheTTL = 60 * 1e3;
|
|
1550
|
+
}
|
|
1551
|
+
// 1 minute cache
|
|
1552
|
+
async getPrice(symbol) {
|
|
1553
|
+
const upperSymbol = symbol.toUpperCase();
|
|
1554
|
+
const cached = this.cache.get(upperSymbol);
|
|
1555
|
+
if (cached && Date.now() - cached.timestamp < this.cacheTTL) {
|
|
1556
|
+
return cached.price;
|
|
1557
|
+
}
|
|
1558
|
+
const coinId = COINGECKO_IDS[upperSymbol];
|
|
1559
|
+
if (!coinId) {
|
|
1560
|
+
return this.getFallbackPrice(upperSymbol);
|
|
1561
|
+
}
|
|
1562
|
+
try {
|
|
1563
|
+
const response = await fetch(
|
|
1564
|
+
`${COINGECKO_API}/simple/price?ids=${coinId}&vs_currencies=usd&include_24hr_change=true&include_market_cap=true&include_24hr_vol=true`,
|
|
1565
|
+
{ headers: { Accept: "application/json" } }
|
|
1566
|
+
);
|
|
1567
|
+
if (!response.ok) {
|
|
1568
|
+
throw new Error(`CoinGecko API error: ${response.status}`);
|
|
1569
|
+
}
|
|
1570
|
+
const data = await response.json();
|
|
1571
|
+
const coinData = data[coinId];
|
|
1572
|
+
if (!coinData) {
|
|
1573
|
+
return this.getFallbackPrice(upperSymbol);
|
|
1574
|
+
}
|
|
1575
|
+
const change24h = coinData.usd_24h_change || 0;
|
|
1576
|
+
const price = {
|
|
1577
|
+
symbol: upperSymbol,
|
|
1578
|
+
price: coinData.usd || 0,
|
|
1579
|
+
change24h,
|
|
1580
|
+
changePercent24h: change24h,
|
|
1581
|
+
priceChange24h: change24h,
|
|
1582
|
+
marketCap: coinData.usd_market_cap,
|
|
1583
|
+
volume24h: coinData.usd_24h_vol
|
|
1584
|
+
};
|
|
1585
|
+
this.cache.set(upperSymbol, { price, timestamp: Date.now() });
|
|
1586
|
+
return price;
|
|
1587
|
+
} catch (error) {
|
|
1588
|
+
console.warn(`Failed to fetch price for ${upperSymbol}:`, error);
|
|
1589
|
+
return this.getFallbackPrice(upperSymbol);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
async getPrices(symbols) {
|
|
1593
|
+
const results = {};
|
|
1594
|
+
const withIds = [];
|
|
1595
|
+
const withoutIds = [];
|
|
1596
|
+
for (const symbol of symbols) {
|
|
1597
|
+
const upper = symbol.toUpperCase();
|
|
1598
|
+
if (COINGECKO_IDS[upper]) {
|
|
1599
|
+
withIds.push(upper);
|
|
1600
|
+
} else {
|
|
1601
|
+
withoutIds.push(upper);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
for (const symbol of withoutIds) {
|
|
1605
|
+
results[symbol] = this.getFallbackPrice(symbol);
|
|
1606
|
+
}
|
|
1607
|
+
if (withIds.length === 0) {
|
|
1608
|
+
return results;
|
|
1609
|
+
}
|
|
1610
|
+
const coinIds = withIds.map((s) => COINGECKO_IDS[s]).join(",");
|
|
1611
|
+
try {
|
|
1612
|
+
const response = await fetch(
|
|
1613
|
+
`${COINGECKO_API}/simple/price?ids=${coinIds}&vs_currencies=usd&include_24hr_change=true`,
|
|
1614
|
+
{ headers: { Accept: "application/json" } }
|
|
1615
|
+
);
|
|
1616
|
+
if (!response.ok) {
|
|
1617
|
+
throw new Error(`CoinGecko API error: ${response.status}`);
|
|
1618
|
+
}
|
|
1619
|
+
const data = await response.json();
|
|
1620
|
+
for (const symbol of withIds) {
|
|
1621
|
+
const coinId = COINGECKO_IDS[symbol];
|
|
1622
|
+
const coinData = data[coinId];
|
|
1623
|
+
if (coinData) {
|
|
1624
|
+
const change24h = coinData.usd_24h_change || 0;
|
|
1625
|
+
results[symbol] = {
|
|
1626
|
+
symbol,
|
|
1627
|
+
price: coinData.usd || 0,
|
|
1628
|
+
change24h,
|
|
1629
|
+
changePercent24h: change24h,
|
|
1630
|
+
priceChange24h: change24h
|
|
1631
|
+
};
|
|
1632
|
+
} else {
|
|
1633
|
+
results[symbol] = this.getFallbackPrice(symbol);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
} catch (error) {
|
|
1637
|
+
console.warn("Failed to fetch batch prices:", error);
|
|
1638
|
+
for (const symbol of withIds) {
|
|
1639
|
+
results[symbol] = this.getFallbackPrice(symbol);
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
return results;
|
|
1643
|
+
}
|
|
1644
|
+
getFallbackPrice(symbol) {
|
|
1645
|
+
const price = FALLBACK_PRICES[symbol] || 0;
|
|
1646
|
+
return {
|
|
1647
|
+
symbol,
|
|
1648
|
+
price,
|
|
1649
|
+
change24h: 0,
|
|
1650
|
+
changePercent24h: 0,
|
|
1651
|
+
priceChange24h: 0
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
clearCache() {
|
|
1655
|
+
this.cache.clear();
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
var priceService = new PriceService();
|
|
1659
|
+
var OneContext = createContext(null);
|
|
1660
|
+
function OneProvider({
|
|
1661
|
+
children,
|
|
1662
|
+
config: config2,
|
|
1663
|
+
autoFetchBalance = true
|
|
1664
|
+
}) {
|
|
1665
|
+
const [isInitialized2, setIsInitialized] = useState(false);
|
|
1666
|
+
const engine = useMemo(() => createOneEngineClient({
|
|
1667
|
+
baseUrl: config2.oneEngineUrl,
|
|
1668
|
+
clientId: config2.oneClientId,
|
|
1669
|
+
secretKey: config2.oneSecretKey
|
|
1670
|
+
}), [config2]);
|
|
1671
|
+
useEffect(() => {
|
|
1672
|
+
initOneSDK(config2);
|
|
1673
|
+
setIsInitialized(true);
|
|
1674
|
+
}, [config2]);
|
|
1675
|
+
const [user, setUser] = useState(null);
|
|
1676
|
+
const [accessToken, setAccessToken] = useState(null);
|
|
1677
|
+
const [authLoading, setAuthLoading] = useState(true);
|
|
1678
|
+
const sendOtp = useCallback(async (email) => {
|
|
1679
|
+
const result = await engine.sendEmailOtp(email);
|
|
1680
|
+
if (!result.success) {
|
|
1681
|
+
return { success: false, error: result.error?.message };
|
|
1682
|
+
}
|
|
1683
|
+
return { success: true };
|
|
1684
|
+
}, [engine]);
|
|
1685
|
+
const verifyOtp = useCallback(async (email, otp) => {
|
|
1686
|
+
const result = await engine.verifyEmailOtp(email, otp);
|
|
1687
|
+
if (!result.success || !result.data) {
|
|
1688
|
+
return { success: false, error: result.error?.message };
|
|
1689
|
+
}
|
|
1690
|
+
const { user: authUser, accessToken: token } = result.data;
|
|
1691
|
+
setUser(authUser);
|
|
1692
|
+
setAccessToken(token);
|
|
1693
|
+
engine.setAccessToken(token);
|
|
1694
|
+
return { success: true };
|
|
1695
|
+
}, [engine]);
|
|
1696
|
+
const signOut = useCallback(async () => {
|
|
1697
|
+
await engine.signOut();
|
|
1698
|
+
setUser(null);
|
|
1699
|
+
setAccessToken(null);
|
|
1700
|
+
engine.clearAccessToken();
|
|
1701
|
+
}, [engine]);
|
|
1702
|
+
const refreshUser = useCallback(async () => {
|
|
1703
|
+
try {
|
|
1704
|
+
if (accessToken) {
|
|
1705
|
+
engine.setAccessToken(accessToken);
|
|
1706
|
+
const result = await engine.getCurrentUser();
|
|
1707
|
+
if (result.success && result.data) {
|
|
1708
|
+
setUser(result.data);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
} finally {
|
|
1712
|
+
setAuthLoading(false);
|
|
1713
|
+
}
|
|
1714
|
+
}, [engine, accessToken]);
|
|
1715
|
+
useEffect(() => {
|
|
1716
|
+
refreshUser();
|
|
1717
|
+
}, []);
|
|
1718
|
+
const [walletAddress, setWalletAddress] = useState(null);
|
|
1719
|
+
const [walletBalance, setWalletBalance] = useState(null);
|
|
1720
|
+
const [walletLoading, setWalletLoading] = useState(false);
|
|
1721
|
+
const [walletError, setWalletError] = useState(null);
|
|
1722
|
+
const fetchBalance = useCallback(async (chains) => {
|
|
1723
|
+
if (!walletAddress) return;
|
|
1724
|
+
setWalletLoading(true);
|
|
1725
|
+
setWalletError(null);
|
|
1726
|
+
try {
|
|
1727
|
+
const result = await engine.getWalletBalance(walletAddress, chains);
|
|
1728
|
+
if (result.success && result.data) {
|
|
1729
|
+
setWalletBalance(result.data);
|
|
1730
|
+
} else {
|
|
1731
|
+
setWalletError(result.error?.message || "Failed to fetch balance");
|
|
1732
|
+
}
|
|
1733
|
+
} catch (error) {
|
|
1734
|
+
setWalletError(error instanceof Error ? error.message : "Failed to fetch balance");
|
|
1735
|
+
} finally {
|
|
1736
|
+
setWalletLoading(false);
|
|
1737
|
+
}
|
|
1738
|
+
}, [walletAddress, engine]);
|
|
1739
|
+
const refreshBalance = useCallback(async () => {
|
|
1740
|
+
await fetchBalance();
|
|
1741
|
+
}, [fetchBalance]);
|
|
1742
|
+
useEffect(() => {
|
|
1743
|
+
if (autoFetchBalance && walletAddress && isInitialized2) {
|
|
1744
|
+
fetchBalance();
|
|
1745
|
+
}
|
|
1746
|
+
}, [walletAddress, autoFetchBalance, isInitialized2, fetchBalance]);
|
|
1747
|
+
const [onrampOpen, setOnrampOpen] = useState(false);
|
|
1748
|
+
const [onrampUrl, setOnrampUrl] = useState(null);
|
|
1749
|
+
const [onrampSessionId, setOnrampSessionId] = useState(null);
|
|
1750
|
+
const openOnramp = useCallback(async (options) => {
|
|
1751
|
+
if (!walletAddress) return;
|
|
1752
|
+
const result = await engine.createOnrampSession({
|
|
1753
|
+
walletAddress,
|
|
1754
|
+
fiatCurrency: "USD",
|
|
1755
|
+
cryptoCurrency: "ETH",
|
|
1756
|
+
...options
|
|
1757
|
+
});
|
|
1758
|
+
if (result.success && result.data) {
|
|
1759
|
+
setOnrampUrl(result.data.widgetUrl);
|
|
1760
|
+
setOnrampSessionId(result.data.sessionId);
|
|
1761
|
+
setOnrampOpen(true);
|
|
1762
|
+
}
|
|
1763
|
+
}, [walletAddress, engine]);
|
|
1764
|
+
const closeOnramp = useCallback(() => {
|
|
1765
|
+
setOnrampOpen(false);
|
|
1766
|
+
setOnrampUrl(null);
|
|
1767
|
+
}, []);
|
|
1768
|
+
const getOnrampQuote = useCallback(async (fiatCurrency, fiatAmount, cryptoCurrency) => {
|
|
1769
|
+
const result = await engine.getOnrampQuote(fiatCurrency, fiatAmount, cryptoCurrency);
|
|
1770
|
+
return result.success ? result.data : null;
|
|
1771
|
+
}, [engine]);
|
|
1772
|
+
const getSwapQuote = useCallback(async (request) => {
|
|
1773
|
+
const result = await engine.getSwapQuote(request);
|
|
1774
|
+
return result.success ? result.data || null : null;
|
|
1775
|
+
}, [engine]);
|
|
1776
|
+
const executeSwap = useCallback(async (quoteId) => {
|
|
1777
|
+
if (!walletAddress) return null;
|
|
1778
|
+
const result = await engine.executeSwap({ quoteId, walletAddress });
|
|
1779
|
+
return result.success ? result.data : null;
|
|
1780
|
+
}, [engine, walletAddress]);
|
|
1781
|
+
const getSupportedTokens = useCallback(async (chainId) => {
|
|
1782
|
+
const result = await engine.getSupportedSwapTokens(chainId);
|
|
1783
|
+
return result.success && result.data ? result.data.tokens : [];
|
|
1784
|
+
}, [engine]);
|
|
1785
|
+
const getSupportedChains = useCallback(async () => {
|
|
1786
|
+
const result = await engine.getSupportedSwapChains();
|
|
1787
|
+
return result.success && result.data ? result.data.chains : [];
|
|
1788
|
+
}, [engine]);
|
|
1789
|
+
const [strategies, setStrategies] = useState([]);
|
|
1790
|
+
const [orders, setOrders] = useState([]);
|
|
1791
|
+
const [portfolioStats, setPortfolioStats] = useState(null);
|
|
1792
|
+
const [tradingLoading, setTradingLoading] = useState(false);
|
|
1793
|
+
const fetchStrategies = useCallback(async () => {
|
|
1794
|
+
setTradingLoading(true);
|
|
1795
|
+
try {
|
|
1796
|
+
const result = await engine.getStrategies();
|
|
1797
|
+
if (result.success && result.data) {
|
|
1798
|
+
setStrategies(result.data);
|
|
1799
|
+
}
|
|
1800
|
+
} finally {
|
|
1801
|
+
setTradingLoading(false);
|
|
1802
|
+
}
|
|
1803
|
+
}, [engine]);
|
|
1804
|
+
const fetchOrders = useCallback(async () => {
|
|
1805
|
+
const result = await engine.getUserOrders();
|
|
1806
|
+
if (result.success && result.data) {
|
|
1807
|
+
setOrders(result.data);
|
|
1808
|
+
}
|
|
1809
|
+
}, [engine]);
|
|
1810
|
+
const fetchPortfolio = useCallback(async () => {
|
|
1811
|
+
const result = await engine.getPortfolioStats();
|
|
1812
|
+
if (result.success && result.data) {
|
|
1813
|
+
setPortfolioStats(result.data);
|
|
1814
|
+
}
|
|
1815
|
+
}, [engine]);
|
|
1816
|
+
const createOrder = useCallback(async (strategyId, amount, currency) => {
|
|
1817
|
+
const result = await engine.createOrder(strategyId, amount, currency);
|
|
1818
|
+
if (result.success) {
|
|
1819
|
+
await fetchOrders();
|
|
1820
|
+
await fetchPortfolio();
|
|
1821
|
+
}
|
|
1822
|
+
return result;
|
|
1823
|
+
}, [engine, fetchOrders, fetchPortfolio]);
|
|
1824
|
+
const contextValue = useMemo(() => ({
|
|
1825
|
+
isInitialized: isInitialized2,
|
|
1826
|
+
config: isInitialized2 ? config2 : null,
|
|
1827
|
+
engine,
|
|
1828
|
+
auth: {
|
|
1829
|
+
user,
|
|
1830
|
+
isAuthenticated: !!user,
|
|
1831
|
+
isLoading: authLoading,
|
|
1832
|
+
accessToken,
|
|
1833
|
+
sendOtp,
|
|
1834
|
+
verifyOtp,
|
|
1835
|
+
signOut,
|
|
1836
|
+
refreshUser
|
|
1837
|
+
},
|
|
1838
|
+
wallet: {
|
|
1839
|
+
address: walletAddress,
|
|
1840
|
+
balance: walletBalance,
|
|
1841
|
+
tokens: walletBalance?.tokens || [],
|
|
1842
|
+
totalUsd: walletBalance?.totalUsd || 0,
|
|
1843
|
+
isLoading: walletLoading,
|
|
1844
|
+
error: walletError,
|
|
1845
|
+
setAddress: setWalletAddress,
|
|
1846
|
+
fetchBalance,
|
|
1847
|
+
refreshBalance
|
|
1848
|
+
},
|
|
1849
|
+
onramp: {
|
|
1850
|
+
isOpen: onrampOpen,
|
|
1851
|
+
widgetUrl: onrampUrl,
|
|
1852
|
+
sessionId: onrampSessionId,
|
|
1853
|
+
openOnramp,
|
|
1854
|
+
closeOnramp,
|
|
1855
|
+
getQuote: getOnrampQuote
|
|
1856
|
+
},
|
|
1857
|
+
swap: {
|
|
1858
|
+
getQuote: getSwapQuote,
|
|
1859
|
+
executeSwap,
|
|
1860
|
+
getSupportedTokens,
|
|
1861
|
+
getSupportedChains
|
|
1862
|
+
},
|
|
1863
|
+
trading: {
|
|
1864
|
+
strategies,
|
|
1865
|
+
orders,
|
|
1866
|
+
portfolioStats,
|
|
1867
|
+
isLoading: tradingLoading,
|
|
1868
|
+
fetchStrategies,
|
|
1869
|
+
fetchOrders,
|
|
1870
|
+
fetchPortfolio,
|
|
1871
|
+
createOrder
|
|
1872
|
+
}
|
|
1873
|
+
}), [
|
|
1874
|
+
isInitialized2,
|
|
1875
|
+
config2,
|
|
1876
|
+
engine,
|
|
1877
|
+
user,
|
|
1878
|
+
authLoading,
|
|
1879
|
+
accessToken,
|
|
1880
|
+
sendOtp,
|
|
1881
|
+
verifyOtp,
|
|
1882
|
+
signOut,
|
|
1883
|
+
refreshUser,
|
|
1884
|
+
walletAddress,
|
|
1885
|
+
walletBalance,
|
|
1886
|
+
walletLoading,
|
|
1887
|
+
walletError,
|
|
1888
|
+
fetchBalance,
|
|
1889
|
+
refreshBalance,
|
|
1890
|
+
onrampOpen,
|
|
1891
|
+
onrampUrl,
|
|
1892
|
+
onrampSessionId,
|
|
1893
|
+
openOnramp,
|
|
1894
|
+
closeOnramp,
|
|
1895
|
+
getOnrampQuote,
|
|
1896
|
+
getSwapQuote,
|
|
1897
|
+
executeSwap,
|
|
1898
|
+
getSupportedTokens,
|
|
1899
|
+
getSupportedChains,
|
|
1900
|
+
strategies,
|
|
1901
|
+
orders,
|
|
1902
|
+
portfolioStats,
|
|
1903
|
+
tradingLoading,
|
|
1904
|
+
fetchStrategies,
|
|
1905
|
+
fetchOrders,
|
|
1906
|
+
fetchPortfolio,
|
|
1907
|
+
createOrder
|
|
1908
|
+
]);
|
|
1909
|
+
return /* @__PURE__ */ jsx(OneContext.Provider, { value: contextValue, children });
|
|
1910
|
+
}
|
|
1911
|
+
function useOne() {
|
|
1912
|
+
const context = useContext(OneContext);
|
|
1913
|
+
if (!context) {
|
|
1914
|
+
throw new Error("useOne must be used within a OneProvider");
|
|
1915
|
+
}
|
|
1916
|
+
return context;
|
|
1917
|
+
}
|
|
1918
|
+
function useOneAuth() {
|
|
1919
|
+
const { auth } = useOne();
|
|
1920
|
+
return auth;
|
|
1921
|
+
}
|
|
1922
|
+
function useOneWallet() {
|
|
1923
|
+
const { wallet } = useOne();
|
|
1924
|
+
return wallet;
|
|
1925
|
+
}
|
|
1926
|
+
function useOneOnramp() {
|
|
1927
|
+
const { onramp } = useOne();
|
|
1928
|
+
return onramp;
|
|
1929
|
+
}
|
|
1930
|
+
function useOneSwap() {
|
|
1931
|
+
const { swap } = useOne();
|
|
1932
|
+
return swap;
|
|
1933
|
+
}
|
|
1934
|
+
function useOneTrading() {
|
|
1935
|
+
const { trading } = useOne();
|
|
1936
|
+
return trading;
|
|
1937
|
+
}
|
|
1938
|
+
function useOneEngine() {
|
|
1939
|
+
const { engine } = useOne();
|
|
1940
|
+
return engine;
|
|
1941
|
+
}
|
|
1942
|
+
var DEFAULT_AUTH_OPTIONS = {
|
|
1943
|
+
email: true,
|
|
1944
|
+
phone: false,
|
|
1945
|
+
google: true,
|
|
1946
|
+
apple: true,
|
|
1947
|
+
facebook: false,
|
|
1948
|
+
discord: false,
|
|
1949
|
+
passkey: true,
|
|
1950
|
+
guest: false
|
|
1951
|
+
};
|
|
1952
|
+
var ThirdwebClientContext = React2.createContext(null);
|
|
1953
|
+
function useThirdwebClient() {
|
|
1954
|
+
const client = React2.useContext(ThirdwebClientContext);
|
|
1955
|
+
if (!client) {
|
|
1956
|
+
throw new Error("useThirdwebClient must be used within OneThirdwebProvider");
|
|
1957
|
+
}
|
|
1958
|
+
return client;
|
|
1959
|
+
}
|
|
1960
|
+
function createWalletConfig(config2) {
|
|
1961
|
+
const authOptions = { ...DEFAULT_AUTH_OPTIONS, ...config2.authOptions };
|
|
1962
|
+
const authMethods = [];
|
|
1963
|
+
if (authOptions.google) authMethods.push("google");
|
|
1964
|
+
if (authOptions.apple) authMethods.push("apple");
|
|
1965
|
+
if (authOptions.facebook) authMethods.push("facebook");
|
|
1966
|
+
if (authOptions.discord) authMethods.push("discord");
|
|
1967
|
+
if (authOptions.passkey) authMethods.push("passkey");
|
|
1968
|
+
const inApp = inAppWallet({
|
|
1969
|
+
auth: {
|
|
1970
|
+
options: authMethods
|
|
1971
|
+
},
|
|
1972
|
+
metadata: config2.appName ? {
|
|
1973
|
+
name: config2.appName,
|
|
1974
|
+
image: config2.appIcon ? { src: config2.appIcon, width: 100, height: 100 } : void 0
|
|
1975
|
+
} : void 0
|
|
1976
|
+
});
|
|
1977
|
+
if (config2.sponsorGas) {
|
|
1978
|
+
const chain = config2.defaultChain || base;
|
|
1979
|
+
return [
|
|
1980
|
+
smartWallet({
|
|
1981
|
+
chain,
|
|
1982
|
+
sponsorGas: true
|
|
1983
|
+
})
|
|
1984
|
+
];
|
|
1985
|
+
}
|
|
1986
|
+
return [inApp];
|
|
1987
|
+
}
|
|
1988
|
+
var DEFAULT_ENGINE_URL = process.env.NEXT_PUBLIC_ONE_ENGINE_URL || "/api";
|
|
1989
|
+
function OneThirdwebProvider({
|
|
1990
|
+
children,
|
|
1991
|
+
config: config2 = {}
|
|
1992
|
+
}) {
|
|
1993
|
+
const [clientId, setClientId] = useState(null);
|
|
1994
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
1995
|
+
const [error, setError] = useState(null);
|
|
1996
|
+
useEffect(() => {
|
|
1997
|
+
const fetchClientConfig = async () => {
|
|
1998
|
+
try {
|
|
1999
|
+
const engineUrl = config2.engineUrl || DEFAULT_ENGINE_URL;
|
|
2000
|
+
const response = await fetch(`${engineUrl}/v1/config/thirdweb`);
|
|
2001
|
+
if (response.ok) {
|
|
2002
|
+
const data = await response.json();
|
|
2003
|
+
if (data.success && data.data?.clientId) {
|
|
2004
|
+
setClientId(data.data.clientId);
|
|
2005
|
+
} else {
|
|
2006
|
+
const envClientId = process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID;
|
|
2007
|
+
if (envClientId) {
|
|
2008
|
+
setClientId(envClientId);
|
|
2009
|
+
} else {
|
|
2010
|
+
setError("Failed to load wallet configuration");
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
} else {
|
|
2014
|
+
const envClientId = process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID;
|
|
2015
|
+
if (envClientId) {
|
|
2016
|
+
setClientId(envClientId);
|
|
2017
|
+
} else {
|
|
2018
|
+
setError("Wallet service unavailable");
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
} catch (err) {
|
|
2022
|
+
const envClientId = process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID;
|
|
2023
|
+
if (envClientId) {
|
|
2024
|
+
setClientId(envClientId);
|
|
2025
|
+
} else {
|
|
2026
|
+
console.error("Failed to fetch thirdweb config:", err);
|
|
2027
|
+
setError("Failed to initialize wallet");
|
|
2028
|
+
}
|
|
2029
|
+
} finally {
|
|
2030
|
+
setIsLoading(false);
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
fetchClientConfig();
|
|
2034
|
+
}, [config2.engineUrl]);
|
|
2035
|
+
const client = useMemo(() => {
|
|
2036
|
+
if (!clientId) return null;
|
|
2037
|
+
return createThirdwebClient({ clientId });
|
|
2038
|
+
}, [clientId]);
|
|
2039
|
+
useMemo(() => createWalletConfig(config2), [config2]);
|
|
2040
|
+
if (isLoading) {
|
|
2041
|
+
return /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", minHeight: "100px" }, children: /* @__PURE__ */ jsx("span", { style: { color: "#9ca3af" }, children: "Initializing wallet..." }) });
|
|
2042
|
+
}
|
|
2043
|
+
if (error || !client) {
|
|
2044
|
+
return /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", minHeight: "100px" }, children: /* @__PURE__ */ jsx("span", { style: { color: "#ef4444" }, children: error || "Wallet initialization failed" }) });
|
|
2045
|
+
}
|
|
2046
|
+
return /* @__PURE__ */ jsx(ThirdwebClientContext.Provider, { value: client, children: /* @__PURE__ */ jsx(ThirdwebProvider, { children }) });
|
|
2047
|
+
}
|
|
2048
|
+
var ONE_THEME = {
|
|
2049
|
+
colors: {
|
|
2050
|
+
primaryButtonBg: "#10b981",
|
|
2051
|
+
// emerald-500
|
|
2052
|
+
primaryButtonText: "#ffffff"},
|
|
2053
|
+
fontFamily: "Inter, system-ui, sans-serif"
|
|
2054
|
+
};
|
|
2055
|
+
function OneConnectButton({
|
|
2056
|
+
label = "Connect Wallet",
|
|
2057
|
+
theme = "dark",
|
|
2058
|
+
className,
|
|
2059
|
+
style,
|
|
2060
|
+
chain = base,
|
|
2061
|
+
sponsorGas = true,
|
|
2062
|
+
authOptions = {
|
|
2063
|
+
email: true,
|
|
2064
|
+
google: true,
|
|
2065
|
+
apple: true,
|
|
2066
|
+
discord: false,
|
|
2067
|
+
passkey: true
|
|
2068
|
+
},
|
|
2069
|
+
onConnect,
|
|
2070
|
+
onDisconnect,
|
|
2071
|
+
accountAbstraction
|
|
2072
|
+
}) {
|
|
2073
|
+
const client = useThirdwebClient();
|
|
2074
|
+
const authMethods = ["email"];
|
|
2075
|
+
if (authOptions.google) authMethods.push("google");
|
|
2076
|
+
if (authOptions.apple) authMethods.push("apple");
|
|
2077
|
+
if (authOptions.discord) authMethods.push("discord");
|
|
2078
|
+
if (authOptions.passkey) authMethods.push("passkey");
|
|
2079
|
+
const wallet = inAppWallet({
|
|
2080
|
+
auth: {
|
|
2081
|
+
options: authMethods
|
|
2082
|
+
}
|
|
2083
|
+
});
|
|
2084
|
+
const connectProps = {
|
|
2085
|
+
client,
|
|
2086
|
+
wallets: [wallet],
|
|
2087
|
+
connectButton: {
|
|
2088
|
+
label,
|
|
2089
|
+
style: {
|
|
2090
|
+
backgroundColor: ONE_THEME.colors.primaryButtonBg,
|
|
2091
|
+
color: ONE_THEME.colors.primaryButtonText,
|
|
2092
|
+
fontFamily: ONE_THEME.fontFamily,
|
|
2093
|
+
fontWeight: 600,
|
|
2094
|
+
borderRadius: "12px",
|
|
2095
|
+
padding: "12px 24px",
|
|
2096
|
+
...style
|
|
2097
|
+
},
|
|
2098
|
+
className
|
|
2099
|
+
},
|
|
2100
|
+
theme: theme === "dark" ? "dark" : "light"
|
|
2101
|
+
};
|
|
2102
|
+
if (sponsorGas || accountAbstraction) {
|
|
2103
|
+
connectProps.accountAbstraction = {
|
|
2104
|
+
chain: accountAbstraction?.chain || chain,
|
|
2105
|
+
sponsorGas: accountAbstraction?.sponsorGas ?? sponsorGas
|
|
2106
|
+
};
|
|
2107
|
+
}
|
|
2108
|
+
return /* @__PURE__ */ jsx(ConnectButton, { ...connectProps });
|
|
2109
|
+
}
|
|
2110
|
+
function OneConnectButtonSimple(props) {
|
|
2111
|
+
return /* @__PURE__ */ jsx(
|
|
2112
|
+
OneConnectButton,
|
|
2113
|
+
{
|
|
2114
|
+
...props,
|
|
2115
|
+
authOptions: { email: true, google: true, apple: false, passkey: false }
|
|
2116
|
+
}
|
|
2117
|
+
);
|
|
2118
|
+
}
|
|
2119
|
+
function OneConnectButtonFull(props) {
|
|
2120
|
+
return /* @__PURE__ */ jsx(
|
|
2121
|
+
OneConnectButton,
|
|
2122
|
+
{
|
|
2123
|
+
...props,
|
|
2124
|
+
authOptions: { email: true, google: true, apple: true, discord: true, passkey: true }
|
|
2125
|
+
}
|
|
2126
|
+
);
|
|
2127
|
+
}
|
|
2128
|
+
var DEFAULT_SUPPORTED_TOKENS = {
|
|
2129
|
+
[base.id]: [
|
|
2130
|
+
"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
|
|
2131
|
+
// USDC on Base
|
|
2132
|
+
],
|
|
2133
|
+
[ethereum.id]: [
|
|
2134
|
+
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
2135
|
+
// USDC on Ethereum
|
|
2136
|
+
"0xdAC17F958D2ee523a2206206994597C13D831ec7"
|
|
2137
|
+
// USDT on Ethereum
|
|
2138
|
+
],
|
|
2139
|
+
[polygon.id]: [
|
|
2140
|
+
"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
|
|
2141
|
+
// USDC on Polygon
|
|
2142
|
+
],
|
|
2143
|
+
[arbitrum.id]: [
|
|
2144
|
+
"0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
|
|
2145
|
+
// USDC on Arbitrum
|
|
2146
|
+
]
|
|
2147
|
+
};
|
|
2148
|
+
function OnePayWidget({
|
|
2149
|
+
mode = "fund_wallet",
|
|
2150
|
+
recipientAddress,
|
|
2151
|
+
amount,
|
|
2152
|
+
tokenAddress,
|
|
2153
|
+
chainId,
|
|
2154
|
+
transaction,
|
|
2155
|
+
theme = "dark",
|
|
2156
|
+
className,
|
|
2157
|
+
style,
|
|
2158
|
+
buyWithCrypto = true,
|
|
2159
|
+
buyWithFiat = true,
|
|
2160
|
+
supportedTokens = DEFAULT_SUPPORTED_TOKENS,
|
|
2161
|
+
onSuccess,
|
|
2162
|
+
onError,
|
|
2163
|
+
onCancel
|
|
2164
|
+
}) {
|
|
2165
|
+
const client = useThirdwebClient();
|
|
2166
|
+
let payOptions;
|
|
2167
|
+
switch (mode) {
|
|
2168
|
+
case "direct_payment":
|
|
2169
|
+
if (!recipientAddress) {
|
|
2170
|
+
console.warn("OnePayWidget: recipientAddress required for direct_payment mode");
|
|
2171
|
+
}
|
|
2172
|
+
payOptions = {
|
|
2173
|
+
mode: "direct_payment",
|
|
2174
|
+
paymentInfo: {
|
|
2175
|
+
sellerAddress: recipientAddress || "",
|
|
2176
|
+
amount: amount || "0",
|
|
2177
|
+
chain: chainId ? { id: chainId } : base,
|
|
2178
|
+
token: tokenAddress ? { address: tokenAddress } : void 0
|
|
2179
|
+
},
|
|
2180
|
+
buyWithCrypto: buyWithCrypto ? {} : false,
|
|
2181
|
+
buyWithFiat: buyWithFiat ? {} : false
|
|
2182
|
+
};
|
|
2183
|
+
break;
|
|
2184
|
+
case "transaction":
|
|
2185
|
+
if (!transaction) {
|
|
2186
|
+
console.warn("OnePayWidget: transaction required for transaction mode");
|
|
2187
|
+
}
|
|
2188
|
+
payOptions = {
|
|
2189
|
+
mode: "transaction",
|
|
2190
|
+
transaction,
|
|
2191
|
+
buyWithCrypto: buyWithCrypto ? {} : false,
|
|
2192
|
+
buyWithFiat: buyWithFiat ? {} : false
|
|
2193
|
+
};
|
|
2194
|
+
break;
|
|
2195
|
+
case "fund_wallet":
|
|
2196
|
+
default:
|
|
2197
|
+
payOptions = {
|
|
2198
|
+
mode: "fund_wallet",
|
|
2199
|
+
buyWithCrypto: buyWithCrypto ? {} : false,
|
|
2200
|
+
buyWithFiat: buyWithFiat ? {} : false
|
|
2201
|
+
};
|
|
2202
|
+
break;
|
|
2203
|
+
}
|
|
2204
|
+
return /* @__PURE__ */ jsx("div", { className, style, children: /* @__PURE__ */ jsx(
|
|
2205
|
+
PayEmbed,
|
|
2206
|
+
{
|
|
2207
|
+
client,
|
|
2208
|
+
payOptions,
|
|
2209
|
+
theme,
|
|
2210
|
+
supportedTokens
|
|
2211
|
+
}
|
|
2212
|
+
) });
|
|
2213
|
+
}
|
|
2214
|
+
function OneFundWalletWidget(props) {
|
|
2215
|
+
return /* @__PURE__ */ jsx(OnePayWidget, { ...props, mode: "fund_wallet" });
|
|
2216
|
+
}
|
|
2217
|
+
function OneDirectPayWidget(props) {
|
|
2218
|
+
return /* @__PURE__ */ jsx(OnePayWidget, { ...props, mode: "direct_payment" });
|
|
2219
|
+
}
|
|
2220
|
+
function OneCryptoOnlyPayWidget(props) {
|
|
2221
|
+
return /* @__PURE__ */ jsx(OnePayWidget, { ...props, buyWithFiat: false });
|
|
2222
|
+
}
|
|
2223
|
+
function OneFiatOnlyPayWidget(props) {
|
|
2224
|
+
return /* @__PURE__ */ jsx(OnePayWidget, { ...props, buyWithCrypto: false });
|
|
2225
|
+
}
|
|
2226
|
+
var ONE_BUTTON_STYLE = {
|
|
2227
|
+
backgroundColor: "#10b981",
|
|
2228
|
+
color: "#ffffff",
|
|
2229
|
+
fontFamily: "Inter, system-ui, sans-serif",
|
|
2230
|
+
fontWeight: 600,
|
|
2231
|
+
borderRadius: "12px",
|
|
2232
|
+
padding: "12px 24px",
|
|
2233
|
+
border: "none",
|
|
2234
|
+
cursor: "pointer",
|
|
2235
|
+
transition: "background-color 0.2s"
|
|
2236
|
+
};
|
|
2237
|
+
var ONE_BUTTON_DISABLED_STYLE = {
|
|
2238
|
+
...ONE_BUTTON_STYLE,
|
|
2239
|
+
backgroundColor: "#6b7280",
|
|
2240
|
+
cursor: "not-allowed"
|
|
2241
|
+
};
|
|
2242
|
+
function OneTransactionButton({
|
|
2243
|
+
to,
|
|
2244
|
+
value,
|
|
2245
|
+
data,
|
|
2246
|
+
chain,
|
|
2247
|
+
transaction: preparedTx,
|
|
2248
|
+
label = "Send Transaction",
|
|
2249
|
+
loadingLabel = "Processing...",
|
|
2250
|
+
theme = "dark",
|
|
2251
|
+
className,
|
|
2252
|
+
style,
|
|
2253
|
+
disabled = false,
|
|
2254
|
+
onSuccess,
|
|
2255
|
+
onError,
|
|
2256
|
+
onSubmitted
|
|
2257
|
+
}) {
|
|
2258
|
+
const client = useThirdwebClient();
|
|
2259
|
+
const transaction = preparedTx || prepareTransaction({
|
|
2260
|
+
to,
|
|
2261
|
+
value,
|
|
2262
|
+
data,
|
|
2263
|
+
chain,
|
|
2264
|
+
client
|
|
2265
|
+
});
|
|
2266
|
+
const buttonStyle6 = disabled ? { ...ONE_BUTTON_DISABLED_STYLE, ...style } : { ...ONE_BUTTON_STYLE, ...style };
|
|
2267
|
+
return /* @__PURE__ */ jsx(
|
|
2268
|
+
TransactionButton,
|
|
2269
|
+
{
|
|
2270
|
+
transaction: () => transaction,
|
|
2271
|
+
onTransactionSent: (result) => onSubmitted?.(result.transactionHash),
|
|
2272
|
+
onTransactionConfirmed: (result) => onSuccess?.({ transactionHash: result.transactionHash }),
|
|
2273
|
+
onError,
|
|
2274
|
+
disabled,
|
|
2275
|
+
style: buttonStyle6,
|
|
2276
|
+
className,
|
|
2277
|
+
theme,
|
|
2278
|
+
children: label
|
|
2279
|
+
}
|
|
2280
|
+
);
|
|
2281
|
+
}
|
|
2282
|
+
function OneSendETHButton({
|
|
2283
|
+
amount,
|
|
2284
|
+
...props
|
|
2285
|
+
}) {
|
|
2286
|
+
const valueInWei = BigInt(Math.floor(parseFloat(amount) * 1e18));
|
|
2287
|
+
return /* @__PURE__ */ jsx(
|
|
2288
|
+
OneTransactionButton,
|
|
2289
|
+
{
|
|
2290
|
+
...props,
|
|
2291
|
+
value: valueInWei,
|
|
2292
|
+
label: props.label || `Send ${amount} ETH`
|
|
2293
|
+
}
|
|
2294
|
+
);
|
|
2295
|
+
}
|
|
2296
|
+
function OneApproveButton({
|
|
2297
|
+
tokenAddress,
|
|
2298
|
+
spenderAddress,
|
|
2299
|
+
amount = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
|
|
2300
|
+
chain,
|
|
2301
|
+
...props
|
|
2302
|
+
}) {
|
|
2303
|
+
const approveData = `0x095ea7b3${spenderAddress.slice(2).padStart(64, "0")}${amount.toString(16).padStart(64, "0")}`;
|
|
2304
|
+
return /* @__PURE__ */ jsx(
|
|
2305
|
+
OneTransactionButton,
|
|
2306
|
+
{
|
|
2307
|
+
...props,
|
|
2308
|
+
to: tokenAddress,
|
|
2309
|
+
data: approveData,
|
|
2310
|
+
chain,
|
|
2311
|
+
label: props.label || "Approve Token"
|
|
2312
|
+
}
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
var containerStyle = {
|
|
2316
|
+
display: "flex",
|
|
2317
|
+
flexDirection: "column",
|
|
2318
|
+
gap: "16px",
|
|
2319
|
+
padding: "24px",
|
|
2320
|
+
backgroundColor: "#1f2937",
|
|
2321
|
+
borderRadius: "16px",
|
|
2322
|
+
border: "1px solid #374151"
|
|
2323
|
+
};
|
|
2324
|
+
var inputStyle = {
|
|
2325
|
+
width: "100%",
|
|
2326
|
+
padding: "12px 16px",
|
|
2327
|
+
backgroundColor: "#374151",
|
|
2328
|
+
border: "1px solid #4b5563",
|
|
2329
|
+
borderRadius: "12px",
|
|
2330
|
+
color: "#ffffff",
|
|
2331
|
+
fontSize: "16px",
|
|
2332
|
+
outline: "none"
|
|
2333
|
+
};
|
|
2334
|
+
var labelStyle = {
|
|
2335
|
+
color: "#9ca3af",
|
|
2336
|
+
fontSize: "14px",
|
|
2337
|
+
marginBottom: "4px"
|
|
2338
|
+
};
|
|
2339
|
+
var buttonStyle = {
|
|
2340
|
+
width: "100%",
|
|
2341
|
+
padding: "14px",
|
|
2342
|
+
backgroundColor: "#10b981",
|
|
2343
|
+
color: "#ffffff",
|
|
2344
|
+
border: "none",
|
|
2345
|
+
borderRadius: "12px",
|
|
2346
|
+
fontSize: "16px",
|
|
2347
|
+
fontWeight: 600,
|
|
2348
|
+
cursor: "pointer"
|
|
2349
|
+
};
|
|
2350
|
+
var buttonDisabledStyle = {
|
|
2351
|
+
...buttonStyle,
|
|
2352
|
+
backgroundColor: "#6b7280",
|
|
2353
|
+
cursor: "not-allowed"
|
|
2354
|
+
};
|
|
2355
|
+
function OneSendWidget({
|
|
2356
|
+
defaultRecipient = "",
|
|
2357
|
+
defaultAmount = "",
|
|
2358
|
+
defaultChain = base,
|
|
2359
|
+
tokenAddress,
|
|
2360
|
+
tokenSymbol = "ETH",
|
|
2361
|
+
tokenDecimals = 18,
|
|
2362
|
+
theme = "dark",
|
|
2363
|
+
className,
|
|
2364
|
+
style,
|
|
2365
|
+
onSuccess,
|
|
2366
|
+
onError,
|
|
2367
|
+
onCancel
|
|
2368
|
+
}) {
|
|
2369
|
+
const client = useThirdwebClient();
|
|
2370
|
+
const account = useActiveAccount();
|
|
2371
|
+
const { mutate: sendTransaction, isPending } = useSendTransaction();
|
|
2372
|
+
const [recipient, setRecipient] = useState(defaultRecipient);
|
|
2373
|
+
const [amount, setAmount] = useState(defaultAmount);
|
|
2374
|
+
const [error, setError] = useState(null);
|
|
2375
|
+
const isValidAddress2 = (address) => /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
2376
|
+
const isValidAmount = (amt) => !isNaN(parseFloat(amt)) && parseFloat(amt) > 0;
|
|
2377
|
+
const canSend = isValidAddress2(recipient) && isValidAmount(amount) && !isPending;
|
|
2378
|
+
const handleSend = useCallback(async () => {
|
|
2379
|
+
if (!account || !canSend) return;
|
|
2380
|
+
setError(null);
|
|
2381
|
+
try {
|
|
2382
|
+
let tx;
|
|
2383
|
+
if (tokenAddress) {
|
|
2384
|
+
const amountInWei = BigInt(Math.floor(parseFloat(amount) * Math.pow(10, tokenDecimals)));
|
|
2385
|
+
const transferData = `0xa9059cbb${recipient.slice(2).padStart(64, "0")}${amountInWei.toString(16).padStart(64, "0")}`;
|
|
2386
|
+
tx = prepareTransaction({
|
|
2387
|
+
to: tokenAddress,
|
|
2388
|
+
data: transferData,
|
|
2389
|
+
chain: defaultChain,
|
|
2390
|
+
client
|
|
2391
|
+
});
|
|
2392
|
+
} else {
|
|
2393
|
+
tx = prepareTransaction({
|
|
2394
|
+
to: recipient,
|
|
2395
|
+
value: toWei(amount),
|
|
2396
|
+
chain: defaultChain,
|
|
2397
|
+
client
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
sendTransaction(tx, {
|
|
2401
|
+
onSuccess: (result) => {
|
|
2402
|
+
onSuccess?.(result.transactionHash);
|
|
2403
|
+
setRecipient("");
|
|
2404
|
+
setAmount("");
|
|
2405
|
+
},
|
|
2406
|
+
onError: (err) => {
|
|
2407
|
+
setError(err.message);
|
|
2408
|
+
onError?.(err);
|
|
2409
|
+
}
|
|
2410
|
+
});
|
|
2411
|
+
} catch (err) {
|
|
2412
|
+
const error2 = err instanceof Error ? err : new Error("Transaction failed");
|
|
2413
|
+
setError(error2.message);
|
|
2414
|
+
onError?.(error2);
|
|
2415
|
+
}
|
|
2416
|
+
}, [account, canSend, recipient, amount, tokenAddress, tokenDecimals, defaultChain, client, sendTransaction, onSuccess, onError]);
|
|
2417
|
+
const isDark = theme === "dark";
|
|
2418
|
+
return /* @__PURE__ */ jsxs(
|
|
2419
|
+
"div",
|
|
2420
|
+
{
|
|
2421
|
+
className,
|
|
2422
|
+
style: {
|
|
2423
|
+
...containerStyle,
|
|
2424
|
+
backgroundColor: isDark ? "#1f2937" : "#ffffff",
|
|
2425
|
+
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
|
|
2426
|
+
...style
|
|
2427
|
+
},
|
|
2428
|
+
children: [
|
|
2429
|
+
/* @__PURE__ */ jsxs("h3", { style: { color: isDark ? "#ffffff" : "#111827", margin: 0, fontSize: "18px", fontWeight: 600 }, children: [
|
|
2430
|
+
"Send ",
|
|
2431
|
+
tokenSymbol
|
|
2432
|
+
] }),
|
|
2433
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2434
|
+
/* @__PURE__ */ jsx("label", { style: { ...labelStyle, color: isDark ? "#9ca3af" : "#6b7280" }, children: "Recipient Address" }),
|
|
2435
|
+
/* @__PURE__ */ jsx(
|
|
2436
|
+
"input",
|
|
2437
|
+
{
|
|
2438
|
+
type: "text",
|
|
2439
|
+
value: recipient,
|
|
2440
|
+
onChange: (e) => setRecipient(e.target.value),
|
|
2441
|
+
placeholder: "0x...",
|
|
2442
|
+
style: {
|
|
2443
|
+
...inputStyle,
|
|
2444
|
+
backgroundColor: isDark ? "#374151" : "#f3f4f6",
|
|
2445
|
+
color: isDark ? "#ffffff" : "#111827",
|
|
2446
|
+
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
)
|
|
2450
|
+
] }),
|
|
2451
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2452
|
+
/* @__PURE__ */ jsxs("label", { style: { ...labelStyle, color: isDark ? "#9ca3af" : "#6b7280" }, children: [
|
|
2453
|
+
"Amount (",
|
|
2454
|
+
tokenSymbol,
|
|
2455
|
+
")"
|
|
2456
|
+
] }),
|
|
2457
|
+
/* @__PURE__ */ jsx(
|
|
2458
|
+
"input",
|
|
2459
|
+
{
|
|
2460
|
+
type: "number",
|
|
2461
|
+
value: amount,
|
|
2462
|
+
onChange: (e) => setAmount(e.target.value),
|
|
2463
|
+
placeholder: "0.0",
|
|
2464
|
+
min: "0",
|
|
2465
|
+
step: "any",
|
|
2466
|
+
style: {
|
|
2467
|
+
...inputStyle,
|
|
2468
|
+
backgroundColor: isDark ? "#374151" : "#f3f4f6",
|
|
2469
|
+
color: isDark ? "#ffffff" : "#111827",
|
|
2470
|
+
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
)
|
|
2474
|
+
] }),
|
|
2475
|
+
error && /* @__PURE__ */ jsx("div", { style: { color: "#ef4444", fontSize: "14px", padding: "8px 12px", backgroundColor: "rgba(239, 68, 68, 0.1)", borderRadius: "8px" }, children: error }),
|
|
2476
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px" }, children: [
|
|
2477
|
+
onCancel && /* @__PURE__ */ jsx(
|
|
2478
|
+
"button",
|
|
2479
|
+
{
|
|
2480
|
+
onClick: onCancel,
|
|
2481
|
+
style: {
|
|
2482
|
+
...buttonStyle,
|
|
2483
|
+
flex: 1,
|
|
2484
|
+
backgroundColor: "transparent",
|
|
2485
|
+
border: `1px solid ${isDark ? "#4b5563" : "#d1d5db"}`,
|
|
2486
|
+
color: isDark ? "#9ca3af" : "#6b7280"
|
|
2487
|
+
},
|
|
2488
|
+
children: "Cancel"
|
|
2489
|
+
}
|
|
2490
|
+
),
|
|
2491
|
+
/* @__PURE__ */ jsx(
|
|
2492
|
+
"button",
|
|
2493
|
+
{
|
|
2494
|
+
onClick: handleSend,
|
|
2495
|
+
disabled: !canSend,
|
|
2496
|
+
style: canSend ? { ...buttonStyle, flex: 1 } : { ...buttonDisabledStyle, flex: 1 },
|
|
2497
|
+
children: isPending ? "Sending..." : `Send ${tokenSymbol}`
|
|
2498
|
+
}
|
|
2499
|
+
)
|
|
2500
|
+
] })
|
|
2501
|
+
]
|
|
2502
|
+
}
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
2505
|
+
function OneSendETHWidget(props) {
|
|
2506
|
+
return /* @__PURE__ */ jsx(OneSendWidget, { ...props, tokenSymbol: "ETH", tokenDecimals: 18 });
|
|
2507
|
+
}
|
|
2508
|
+
function OneSendUSDCWidget(props) {
|
|
2509
|
+
return /* @__PURE__ */ jsx(OneSendWidget, { ...props, tokenSymbol: "USDC", tokenDecimals: 6 });
|
|
2510
|
+
}
|
|
2511
|
+
var DEFAULT_FIATS = ["USD", "EUR", "GBP", "CNY", "JPY", "KRW", "CAD", "AUD"];
|
|
2512
|
+
var DEFAULT_CRYPTOS = ["USDT", "USDC", "ETH", "BTC", "MATIC", "BNB", "AVAX", "SOL"];
|
|
2513
|
+
var DEFAULT_NETWORKS = ["ethereum", "polygon", "arbitrum", "optimism", "base", "bsc", "avalanche"];
|
|
2514
|
+
var NETWORK_DISPLAY_NAMES = {
|
|
2515
|
+
ethereum: "Ethereum",
|
|
2516
|
+
polygon: "Polygon",
|
|
2517
|
+
arbitrum: "Arbitrum",
|
|
2518
|
+
optimism: "Optimism",
|
|
2519
|
+
base: "Base",
|
|
2520
|
+
bsc: "BNB Chain",
|
|
2521
|
+
avalanche: "Avalanche",
|
|
2522
|
+
solana: "Solana"
|
|
2523
|
+
};
|
|
2524
|
+
var CRYPTO_RATES = {
|
|
2525
|
+
ETH: 3500,
|
|
2526
|
+
BTC: 95e3,
|
|
2527
|
+
USDT: 1,
|
|
2528
|
+
USDC: 1,
|
|
2529
|
+
MATIC: 0.85,
|
|
2530
|
+
BNB: 650,
|
|
2531
|
+
AVAX: 42,
|
|
2532
|
+
SOL: 200,
|
|
2533
|
+
DAI: 1,
|
|
2534
|
+
ARB: 1.2,
|
|
2535
|
+
OP: 2.5
|
|
2536
|
+
};
|
|
2537
|
+
var containerStyle2 = {
|
|
2538
|
+
display: "flex",
|
|
2539
|
+
flexDirection: "column",
|
|
2540
|
+
gap: "16px",
|
|
2541
|
+
padding: "24px",
|
|
2542
|
+
borderRadius: "16px",
|
|
2543
|
+
border: "1px solid",
|
|
2544
|
+
maxWidth: "420px"
|
|
2545
|
+
};
|
|
2546
|
+
var headerStyle = {
|
|
2547
|
+
display: "flex",
|
|
2548
|
+
justifyContent: "space-between",
|
|
2549
|
+
alignItems: "center",
|
|
2550
|
+
marginBottom: "8px"
|
|
2551
|
+
};
|
|
2552
|
+
var selectStyle = {
|
|
2553
|
+
padding: "12px 16px",
|
|
2554
|
+
borderRadius: "12px",
|
|
2555
|
+
fontSize: "16px",
|
|
2556
|
+
outline: "none",
|
|
2557
|
+
cursor: "pointer",
|
|
2558
|
+
appearance: "none",
|
|
2559
|
+
backgroundRepeat: "no-repeat",
|
|
2560
|
+
backgroundPosition: "right 12px center",
|
|
2561
|
+
paddingRight: "40px"
|
|
2562
|
+
};
|
|
2563
|
+
var inputStyle2 = {
|
|
2564
|
+
padding: "12px 16px",
|
|
2565
|
+
borderRadius: "12px",
|
|
2566
|
+
fontSize: "18px",
|
|
2567
|
+
fontWeight: 500,
|
|
2568
|
+
outline: "none",
|
|
2569
|
+
width: "100%",
|
|
2570
|
+
boxSizing: "border-box"
|
|
2571
|
+
};
|
|
2572
|
+
var buttonStyle2 = {
|
|
2573
|
+
width: "100%",
|
|
2574
|
+
padding: "16px",
|
|
2575
|
+
border: "none",
|
|
2576
|
+
borderRadius: "12px",
|
|
2577
|
+
fontSize: "16px",
|
|
2578
|
+
fontWeight: 600,
|
|
2579
|
+
cursor: "pointer",
|
|
2580
|
+
transition: "background-color 0.2s"
|
|
2581
|
+
};
|
|
2582
|
+
var rowStyle = {
|
|
2583
|
+
display: "flex",
|
|
2584
|
+
gap: "12px",
|
|
2585
|
+
alignItems: "center"
|
|
2586
|
+
};
|
|
2587
|
+
var quoteBoxStyle = {
|
|
2588
|
+
padding: "16px",
|
|
2589
|
+
borderRadius: "12px",
|
|
2590
|
+
fontSize: "14px"
|
|
2591
|
+
};
|
|
2592
|
+
function OneOnrampWidget({
|
|
2593
|
+
defaultFiat = "USD",
|
|
2594
|
+
defaultCrypto = "USDT",
|
|
2595
|
+
defaultAmount = 100,
|
|
2596
|
+
defaultNetwork = "base",
|
|
2597
|
+
supportedFiats = DEFAULT_FIATS,
|
|
2598
|
+
supportedCryptos = DEFAULT_CRYPTOS,
|
|
2599
|
+
supportedNetworks = DEFAULT_NETWORKS,
|
|
2600
|
+
email,
|
|
2601
|
+
country,
|
|
2602
|
+
theme = "dark",
|
|
2603
|
+
accentColor = "#10b981",
|
|
2604
|
+
className,
|
|
2605
|
+
style,
|
|
2606
|
+
mode = "form",
|
|
2607
|
+
embedHeight = 600,
|
|
2608
|
+
onSuccess,
|
|
2609
|
+
onError,
|
|
2610
|
+
onClose,
|
|
2611
|
+
onQuoteUpdate
|
|
2612
|
+
}) {
|
|
2613
|
+
const account = useActiveAccount();
|
|
2614
|
+
const walletAddress = account?.address;
|
|
2615
|
+
const [fiatCurrency, setFiatCurrency] = useState(defaultFiat);
|
|
2616
|
+
const [fiatAmount, setFiatAmount] = useState(defaultAmount.toString());
|
|
2617
|
+
const [cryptoCurrency, setCryptoCurrency] = useState(defaultCrypto);
|
|
2618
|
+
const [network, setNetwork] = useState(defaultNetwork);
|
|
2619
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
2620
|
+
const [error, setError] = useState(null);
|
|
2621
|
+
const [quote, setQuote] = useState(null);
|
|
2622
|
+
const [widgetUrl, setWidgetUrl] = useState(null);
|
|
2623
|
+
const isDark = theme === "dark";
|
|
2624
|
+
const calculateQuote = useCallback(() => {
|
|
2625
|
+
const amount = parseFloat(fiatAmount);
|
|
2626
|
+
if (isNaN(amount) || amount <= 0) return null;
|
|
2627
|
+
const cryptoRate = CRYPTO_RATES[cryptoCurrency.toUpperCase()] || 1;
|
|
2628
|
+
const providerFee = amount * 0.035;
|
|
2629
|
+
const networkFee = cryptoCurrency === "ETH" ? 5 : 1;
|
|
2630
|
+
const totalFee = providerFee + networkFee;
|
|
2631
|
+
const netAmount = amount - totalFee;
|
|
2632
|
+
const cryptoAmount = netAmount / cryptoRate;
|
|
2633
|
+
return {
|
|
2634
|
+
fiatCurrency,
|
|
2635
|
+
fiatAmount: amount,
|
|
2636
|
+
cryptoCurrency,
|
|
2637
|
+
cryptoAmount: parseFloat(cryptoAmount.toFixed(8)),
|
|
2638
|
+
network,
|
|
2639
|
+
rate: cryptoRate,
|
|
2640
|
+
fees: {
|
|
2641
|
+
network: networkFee,
|
|
2642
|
+
provider: providerFee,
|
|
2643
|
+
total: totalFee
|
|
2644
|
+
},
|
|
2645
|
+
estimatedTime: "5-15 minutes"
|
|
2646
|
+
};
|
|
2647
|
+
}, [fiatAmount, fiatCurrency, cryptoCurrency, network]);
|
|
2648
|
+
useEffect(() => {
|
|
2649
|
+
const newQuote = calculateQuote();
|
|
2650
|
+
setQuote(newQuote);
|
|
2651
|
+
if (newQuote) {
|
|
2652
|
+
onQuoteUpdate?.(newQuote);
|
|
2653
|
+
}
|
|
2654
|
+
}, [calculateQuote, onQuoteUpdate]);
|
|
2655
|
+
const buildWidgetUrl = useCallback(() => {
|
|
2656
|
+
if (!walletAddress) return null;
|
|
2657
|
+
const baseUrl = "https://buy.onramper.com";
|
|
2658
|
+
const params = new URLSearchParams();
|
|
2659
|
+
const apiKey = process.env.NEXT_PUBLIC_ONRAMPER_API_KEY || "";
|
|
2660
|
+
if (apiKey) {
|
|
2661
|
+
params.append("apiKey", apiKey);
|
|
2662
|
+
}
|
|
2663
|
+
params.append("wallets", `ETH:${walletAddress},MATIC:${walletAddress},BNB:${walletAddress},AVAX:${walletAddress}`);
|
|
2664
|
+
params.append(
|
|
2665
|
+
"networkWallets",
|
|
2666
|
+
`ethereum:${walletAddress},polygon:${walletAddress},arbitrum:${walletAddress},optimism:${walletAddress},base:${walletAddress},bsc:${walletAddress},avalanche:${walletAddress}`
|
|
2667
|
+
);
|
|
2668
|
+
params.append("defaultCrypto", cryptoCurrency);
|
|
2669
|
+
params.append("defaultFiat", fiatCurrency);
|
|
2670
|
+
params.append("defaultAmount", fiatAmount);
|
|
2671
|
+
params.append("mode", "buy");
|
|
2672
|
+
if (network) {
|
|
2673
|
+
params.append("onlyCryptoNetworks", network);
|
|
2674
|
+
}
|
|
2675
|
+
if (email) params.append("email", email);
|
|
2676
|
+
if (country) params.append("country", country);
|
|
2677
|
+
params.append("color", accentColor.replace("#", ""));
|
|
2678
|
+
params.append("darkMode", isDark ? "true" : "false");
|
|
2679
|
+
params.append("hideTopBar", "false");
|
|
2680
|
+
params.append("isInAppBrowser", "true");
|
|
2681
|
+
params.append("partnerContext", `onesdk_${Date.now()}`);
|
|
2682
|
+
params.append("popularCryptos", "USDT,USDC,ETH,BTC");
|
|
2683
|
+
return `${baseUrl}?${params.toString()}`;
|
|
2684
|
+
}, [walletAddress, cryptoCurrency, fiatCurrency, fiatAmount, network, email, country, accentColor, isDark]);
|
|
2685
|
+
const handleBuy = async () => {
|
|
2686
|
+
if (!walletAddress) {
|
|
2687
|
+
setError("Please connect your wallet first");
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
const amount = parseFloat(fiatAmount);
|
|
2691
|
+
if (isNaN(amount) || amount < 10) {
|
|
2692
|
+
setError("Minimum amount is $10");
|
|
2693
|
+
return;
|
|
2694
|
+
}
|
|
2695
|
+
setIsLoading(true);
|
|
2696
|
+
setError(null);
|
|
2697
|
+
try {
|
|
2698
|
+
const engineUrl = getEngineUrl();
|
|
2699
|
+
const response = await fetch(`${engineUrl}/v1/fiat/onramp`, {
|
|
2700
|
+
method: "POST",
|
|
2701
|
+
headers: { "Content-Type": "application/json" },
|
|
2702
|
+
body: JSON.stringify({
|
|
2703
|
+
walletAddress,
|
|
2704
|
+
fiatCurrency,
|
|
2705
|
+
fiatAmount: amount,
|
|
2706
|
+
cryptoCurrency,
|
|
2707
|
+
network,
|
|
2708
|
+
email
|
|
2709
|
+
})
|
|
2710
|
+
});
|
|
2711
|
+
if (response.ok) {
|
|
2712
|
+
const data = await response.json();
|
|
2713
|
+
if (data.success && data.data?.widgetUrl) {
|
|
2714
|
+
setWidgetUrl(data.data.widgetUrl);
|
|
2715
|
+
if (mode === "popup") {
|
|
2716
|
+
window.open(data.data.widgetUrl, "_blank", "width=450,height=700");
|
|
2717
|
+
}
|
|
2718
|
+
return;
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
const directUrl = buildWidgetUrl();
|
|
2722
|
+
if (directUrl) {
|
|
2723
|
+
setWidgetUrl(directUrl);
|
|
2724
|
+
if (mode === "popup") {
|
|
2725
|
+
window.open(directUrl, "_blank", "width=450,height=700");
|
|
2726
|
+
}
|
|
2727
|
+
} else {
|
|
2728
|
+
throw new Error("Failed to generate widget URL");
|
|
2729
|
+
}
|
|
2730
|
+
} catch (err) {
|
|
2731
|
+
const error2 = err instanceof Error ? err : new Error("Failed to start purchase");
|
|
2732
|
+
setError(error2.message);
|
|
2733
|
+
onError?.(error2);
|
|
2734
|
+
} finally {
|
|
2735
|
+
setIsLoading(false);
|
|
2736
|
+
}
|
|
2737
|
+
};
|
|
2738
|
+
const handleCloseEmbed = () => {
|
|
2739
|
+
setWidgetUrl(null);
|
|
2740
|
+
onClose?.();
|
|
2741
|
+
};
|
|
2742
|
+
const bgColor = isDark ? "#1f2937" : "#ffffff";
|
|
2743
|
+
const borderColor = isDark ? "#374151" : "#e5e7eb";
|
|
2744
|
+
const textColor = isDark ? "#ffffff" : "#111827";
|
|
2745
|
+
const mutedColor = isDark ? "#9ca3af" : "#6b7280";
|
|
2746
|
+
const inputBg = isDark ? "#374151" : "#f3f4f6";
|
|
2747
|
+
const quoteBg = isDark ? "#374151" : "#f3f4f6";
|
|
2748
|
+
if (mode === "embed" && widgetUrl) {
|
|
2749
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { ...style }, children: [
|
|
2750
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end", marginBottom: "8px" }, children: /* @__PURE__ */ jsx(
|
|
2751
|
+
"button",
|
|
2752
|
+
{
|
|
2753
|
+
onClick: handleCloseEmbed,
|
|
2754
|
+
style: {
|
|
2755
|
+
background: "none",
|
|
2756
|
+
border: "none",
|
|
2757
|
+
color: mutedColor,
|
|
2758
|
+
cursor: "pointer",
|
|
2759
|
+
fontSize: "14px"
|
|
2760
|
+
},
|
|
2761
|
+
children: "Close"
|
|
2762
|
+
}
|
|
2763
|
+
) }),
|
|
2764
|
+
/* @__PURE__ */ jsx(
|
|
2765
|
+
"iframe",
|
|
2766
|
+
{
|
|
2767
|
+
src: widgetUrl,
|
|
2768
|
+
width: "100%",
|
|
2769
|
+
height: embedHeight,
|
|
2770
|
+
style: { border: "none", borderRadius: "16px" },
|
|
2771
|
+
allow: "payment; clipboard-read; clipboard-write"
|
|
2772
|
+
}
|
|
2773
|
+
)
|
|
2774
|
+
] });
|
|
2775
|
+
}
|
|
2776
|
+
return /* @__PURE__ */ jsxs(
|
|
2777
|
+
"div",
|
|
2778
|
+
{
|
|
2779
|
+
className,
|
|
2780
|
+
style: {
|
|
2781
|
+
...containerStyle2,
|
|
2782
|
+
backgroundColor: bgColor,
|
|
2783
|
+
borderColor,
|
|
2784
|
+
...style
|
|
2785
|
+
},
|
|
2786
|
+
children: [
|
|
2787
|
+
/* @__PURE__ */ jsxs("div", { style: headerStyle, children: [
|
|
2788
|
+
/* @__PURE__ */ jsx("h3", { style: { color: textColor, margin: 0, fontSize: "18px", fontWeight: 600 }, children: "Buy Crypto" }),
|
|
2789
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor, fontSize: "12px" }, children: "Powered by Onramper" })
|
|
2790
|
+
] }),
|
|
2791
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2792
|
+
/* @__PURE__ */ jsx("label", { style: { color: mutedColor, fontSize: "14px", marginBottom: "8px", display: "block" }, children: "You Pay" }),
|
|
2793
|
+
/* @__PURE__ */ jsxs("div", { style: rowStyle, children: [
|
|
2794
|
+
/* @__PURE__ */ jsx(
|
|
2795
|
+
"input",
|
|
2796
|
+
{
|
|
2797
|
+
type: "number",
|
|
2798
|
+
value: fiatAmount,
|
|
2799
|
+
onChange: (e) => setFiatAmount(e.target.value),
|
|
2800
|
+
placeholder: "0",
|
|
2801
|
+
min: "10",
|
|
2802
|
+
style: {
|
|
2803
|
+
...inputStyle2,
|
|
2804
|
+
flex: 1,
|
|
2805
|
+
backgroundColor: inputBg,
|
|
2806
|
+
border: `1px solid ${borderColor}`,
|
|
2807
|
+
color: textColor
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
),
|
|
2811
|
+
/* @__PURE__ */ jsx(
|
|
2812
|
+
"select",
|
|
2813
|
+
{
|
|
2814
|
+
value: fiatCurrency,
|
|
2815
|
+
onChange: (e) => setFiatCurrency(e.target.value),
|
|
2816
|
+
style: {
|
|
2817
|
+
...selectStyle,
|
|
2818
|
+
backgroundColor: inputBg,
|
|
2819
|
+
border: `1px solid ${borderColor}`,
|
|
2820
|
+
color: textColor,
|
|
2821
|
+
minWidth: "100px",
|
|
2822
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
2823
|
+
backgroundSize: "16px"
|
|
2824
|
+
},
|
|
2825
|
+
children: supportedFiats.map((fiat) => /* @__PURE__ */ jsx("option", { value: fiat, children: fiat }, fiat))
|
|
2826
|
+
}
|
|
2827
|
+
)
|
|
2828
|
+
] })
|
|
2829
|
+
] }),
|
|
2830
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2831
|
+
/* @__PURE__ */ jsx("label", { style: { color: mutedColor, fontSize: "14px", marginBottom: "8px", display: "block" }, children: "You Receive" }),
|
|
2832
|
+
/* @__PURE__ */ jsxs("div", { style: rowStyle, children: [
|
|
2833
|
+
/* @__PURE__ */ jsx(
|
|
2834
|
+
"div",
|
|
2835
|
+
{
|
|
2836
|
+
style: {
|
|
2837
|
+
...inputStyle2,
|
|
2838
|
+
flex: 1,
|
|
2839
|
+
backgroundColor: inputBg,
|
|
2840
|
+
border: `1px solid ${borderColor}`,
|
|
2841
|
+
color: textColor,
|
|
2842
|
+
display: "flex",
|
|
2843
|
+
alignItems: "center"
|
|
2844
|
+
},
|
|
2845
|
+
children: /* @__PURE__ */ jsx("span", { style: { color: quote ? textColor : mutedColor }, children: quote ? `~${quote.cryptoAmount.toFixed(6)}` : "0.00" })
|
|
2846
|
+
}
|
|
2847
|
+
),
|
|
2848
|
+
/* @__PURE__ */ jsx(
|
|
2849
|
+
"select",
|
|
2850
|
+
{
|
|
2851
|
+
value: cryptoCurrency,
|
|
2852
|
+
onChange: (e) => setCryptoCurrency(e.target.value),
|
|
2853
|
+
style: {
|
|
2854
|
+
...selectStyle,
|
|
2855
|
+
backgroundColor: inputBg,
|
|
2856
|
+
border: `1px solid ${borderColor}`,
|
|
2857
|
+
color: textColor,
|
|
2858
|
+
minWidth: "100px",
|
|
2859
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
2860
|
+
backgroundSize: "16px"
|
|
2861
|
+
},
|
|
2862
|
+
children: supportedCryptos.map((crypto) => /* @__PURE__ */ jsx("option", { value: crypto, children: crypto }, crypto))
|
|
2863
|
+
}
|
|
2864
|
+
)
|
|
2865
|
+
] })
|
|
2866
|
+
] }),
|
|
2867
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2868
|
+
/* @__PURE__ */ jsx("label", { style: { color: mutedColor, fontSize: "14px", marginBottom: "8px", display: "block" }, children: "Network" }),
|
|
2869
|
+
/* @__PURE__ */ jsx(
|
|
2870
|
+
"select",
|
|
2871
|
+
{
|
|
2872
|
+
value: network,
|
|
2873
|
+
onChange: (e) => setNetwork(e.target.value),
|
|
2874
|
+
style: {
|
|
2875
|
+
...selectStyle,
|
|
2876
|
+
width: "100%",
|
|
2877
|
+
backgroundColor: inputBg,
|
|
2878
|
+
border: `1px solid ${borderColor}`,
|
|
2879
|
+
color: textColor,
|
|
2880
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
2881
|
+
backgroundSize: "16px"
|
|
2882
|
+
},
|
|
2883
|
+
children: supportedNetworks.map((net) => /* @__PURE__ */ jsx("option", { value: net, children: NETWORK_DISPLAY_NAMES[net] || net }, net))
|
|
2884
|
+
}
|
|
2885
|
+
)
|
|
2886
|
+
] }),
|
|
2887
|
+
quote && /* @__PURE__ */ jsxs("div", { style: { ...quoteBoxStyle, backgroundColor: quoteBg }, children: [
|
|
2888
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
|
|
2889
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Rate" }),
|
|
2890
|
+
/* @__PURE__ */ jsxs("span", { style: { color: textColor }, children: [
|
|
2891
|
+
"1 ",
|
|
2892
|
+
cryptoCurrency,
|
|
2893
|
+
" = $",
|
|
2894
|
+
quote.rate.toLocaleString()
|
|
2895
|
+
] })
|
|
2896
|
+
] }),
|
|
2897
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
|
|
2898
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Fees" }),
|
|
2899
|
+
/* @__PURE__ */ jsxs("span", { style: { color: textColor }, children: [
|
|
2900
|
+
"~$",
|
|
2901
|
+
quote.fees.total.toFixed(2)
|
|
2902
|
+
] })
|
|
2903
|
+
] }),
|
|
2904
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
2905
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Est. Time" }),
|
|
2906
|
+
/* @__PURE__ */ jsx("span", { style: { color: textColor }, children: quote.estimatedTime })
|
|
2907
|
+
] })
|
|
2908
|
+
] }),
|
|
2909
|
+
error && /* @__PURE__ */ jsx("div", { style: {
|
|
2910
|
+
color: "#ef4444",
|
|
2911
|
+
fontSize: "14px",
|
|
2912
|
+
padding: "12px",
|
|
2913
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
2914
|
+
borderRadius: "8px"
|
|
2915
|
+
}, children: error }),
|
|
2916
|
+
/* @__PURE__ */ jsx(
|
|
2917
|
+
"button",
|
|
2918
|
+
{
|
|
2919
|
+
onClick: handleBuy,
|
|
2920
|
+
disabled: isLoading || !walletAddress,
|
|
2921
|
+
style: {
|
|
2922
|
+
...buttonStyle2,
|
|
2923
|
+
backgroundColor: isLoading || !walletAddress ? "#6b7280" : accentColor,
|
|
2924
|
+
color: "#ffffff",
|
|
2925
|
+
cursor: isLoading || !walletAddress ? "not-allowed" : "pointer"
|
|
2926
|
+
},
|
|
2927
|
+
children: isLoading ? "Loading..." : !walletAddress ? "Connect Wallet" : `Buy ${cryptoCurrency}`
|
|
2928
|
+
}
|
|
2929
|
+
),
|
|
2930
|
+
walletAddress && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", color: mutedColor, fontSize: "12px" }, children: [
|
|
2931
|
+
"Receiving to: ",
|
|
2932
|
+
walletAddress.slice(0, 6),
|
|
2933
|
+
"...",
|
|
2934
|
+
walletAddress.slice(-4)
|
|
2935
|
+
] })
|
|
2936
|
+
]
|
|
2937
|
+
}
|
|
2938
|
+
);
|
|
2939
|
+
}
|
|
2940
|
+
function OneBuyUSDTWidget(props) {
|
|
2941
|
+
return /* @__PURE__ */ jsx(OneOnrampWidget, { ...props, defaultCrypto: "USDT" });
|
|
2942
|
+
}
|
|
2943
|
+
function OneBuyUSDCWidget(props) {
|
|
2944
|
+
return /* @__PURE__ */ jsx(OneOnrampWidget, { ...props, defaultCrypto: "USDC" });
|
|
2945
|
+
}
|
|
2946
|
+
function OneBuyETHWidget(props) {
|
|
2947
|
+
return /* @__PURE__ */ jsx(OneOnrampWidget, { ...props, defaultCrypto: "ETH" });
|
|
2948
|
+
}
|
|
2949
|
+
function OneBuyBTCWidget(props) {
|
|
2950
|
+
return /* @__PURE__ */ jsx(OneOnrampWidget, { ...props, defaultCrypto: "BTC" });
|
|
2951
|
+
}
|
|
2952
|
+
var DEFAULT_FIATS2 = ["USD", "EUR", "GBP", "CNY", "JPY", "KRW", "CAD", "AUD"];
|
|
2953
|
+
var DEFAULT_CRYPTOS2 = ["USDT", "USDC", "ETH", "BTC", "MATIC", "BNB"];
|
|
2954
|
+
var DEFAULT_NETWORKS2 = ["ethereum", "polygon", "arbitrum", "optimism", "base", "bsc", "avalanche"];
|
|
2955
|
+
var NETWORK_DISPLAY_NAMES2 = {
|
|
2956
|
+
ethereum: "Ethereum",
|
|
2957
|
+
polygon: "Polygon",
|
|
2958
|
+
arbitrum: "Arbitrum",
|
|
2959
|
+
optimism: "Optimism",
|
|
2960
|
+
base: "Base",
|
|
2961
|
+
bsc: "BNB Chain",
|
|
2962
|
+
avalanche: "Avalanche",
|
|
2963
|
+
solana: "Solana"
|
|
2964
|
+
};
|
|
2965
|
+
var CRYPTO_RATES2 = {
|
|
2966
|
+
ETH: 3500,
|
|
2967
|
+
BTC: 95e3,
|
|
2968
|
+
USDT: 1,
|
|
2969
|
+
USDC: 1,
|
|
2970
|
+
MATIC: 0.85,
|
|
2971
|
+
BNB: 650,
|
|
2972
|
+
AVAX: 42,
|
|
2973
|
+
SOL: 200,
|
|
2974
|
+
DAI: 1
|
|
2975
|
+
};
|
|
2976
|
+
var containerStyle3 = {
|
|
2977
|
+
display: "flex",
|
|
2978
|
+
flexDirection: "column",
|
|
2979
|
+
gap: "16px",
|
|
2980
|
+
padding: "24px",
|
|
2981
|
+
borderRadius: "16px",
|
|
2982
|
+
border: "1px solid",
|
|
2983
|
+
maxWidth: "420px"
|
|
2984
|
+
};
|
|
2985
|
+
var headerStyle2 = {
|
|
2986
|
+
display: "flex",
|
|
2987
|
+
justifyContent: "space-between",
|
|
2988
|
+
alignItems: "center",
|
|
2989
|
+
marginBottom: "8px"
|
|
2990
|
+
};
|
|
2991
|
+
var selectStyle2 = {
|
|
2992
|
+
padding: "12px 16px",
|
|
2993
|
+
borderRadius: "12px",
|
|
2994
|
+
fontSize: "16px",
|
|
2995
|
+
outline: "none",
|
|
2996
|
+
cursor: "pointer",
|
|
2997
|
+
appearance: "none",
|
|
2998
|
+
backgroundRepeat: "no-repeat",
|
|
2999
|
+
backgroundPosition: "right 12px center",
|
|
3000
|
+
paddingRight: "40px"
|
|
3001
|
+
};
|
|
3002
|
+
var inputStyle3 = {
|
|
3003
|
+
padding: "12px 16px",
|
|
3004
|
+
borderRadius: "12px",
|
|
3005
|
+
fontSize: "18px",
|
|
3006
|
+
fontWeight: 500,
|
|
3007
|
+
outline: "none",
|
|
3008
|
+
width: "100%",
|
|
3009
|
+
boxSizing: "border-box"
|
|
3010
|
+
};
|
|
3011
|
+
var buttonStyle3 = {
|
|
3012
|
+
width: "100%",
|
|
3013
|
+
padding: "16px",
|
|
3014
|
+
border: "none",
|
|
3015
|
+
borderRadius: "12px",
|
|
3016
|
+
fontSize: "16px",
|
|
3017
|
+
fontWeight: 600,
|
|
3018
|
+
cursor: "pointer",
|
|
3019
|
+
transition: "background-color 0.2s"
|
|
3020
|
+
};
|
|
3021
|
+
var rowStyle2 = {
|
|
3022
|
+
display: "flex",
|
|
3023
|
+
gap: "12px",
|
|
3024
|
+
alignItems: "center"
|
|
3025
|
+
};
|
|
3026
|
+
var quoteBoxStyle2 = {
|
|
3027
|
+
padding: "16px",
|
|
3028
|
+
borderRadius: "12px",
|
|
3029
|
+
fontSize: "14px"
|
|
3030
|
+
};
|
|
3031
|
+
var balanceStyle = {
|
|
3032
|
+
display: "flex",
|
|
3033
|
+
justifyContent: "space-between",
|
|
3034
|
+
fontSize: "12px",
|
|
3035
|
+
marginTop: "4px"
|
|
3036
|
+
};
|
|
3037
|
+
function OneOfframpWidget({
|
|
3038
|
+
defaultFiat = "USD",
|
|
3039
|
+
defaultCrypto = "USDT",
|
|
3040
|
+
defaultAmount = "",
|
|
3041
|
+
defaultNetwork = "base",
|
|
3042
|
+
supportedFiats = DEFAULT_FIATS2,
|
|
3043
|
+
supportedCryptos = DEFAULT_CRYPTOS2,
|
|
3044
|
+
supportedNetworks = DEFAULT_NETWORKS2,
|
|
3045
|
+
email,
|
|
3046
|
+
country,
|
|
3047
|
+
theme = "dark",
|
|
3048
|
+
accentColor = "#ef4444",
|
|
3049
|
+
// Red for sell
|
|
3050
|
+
className,
|
|
3051
|
+
style,
|
|
3052
|
+
mode = "form",
|
|
3053
|
+
embedHeight = 600,
|
|
3054
|
+
onSuccess,
|
|
3055
|
+
onError,
|
|
3056
|
+
onClose,
|
|
3057
|
+
onQuoteUpdate
|
|
3058
|
+
}) {
|
|
3059
|
+
const client = useThirdwebClient();
|
|
3060
|
+
const account = useActiveAccount();
|
|
3061
|
+
const walletAddress = account?.address;
|
|
3062
|
+
const { data: balanceData } = useWalletBalance({
|
|
3063
|
+
client,
|
|
3064
|
+
chain: base,
|
|
3065
|
+
address: walletAddress
|
|
3066
|
+
});
|
|
3067
|
+
const [cryptoCurrency, setCryptoCurrency] = useState(defaultCrypto);
|
|
3068
|
+
const [cryptoAmount, setCryptoAmount] = useState(defaultAmount);
|
|
3069
|
+
const [fiatCurrency, setFiatCurrency] = useState(defaultFiat);
|
|
3070
|
+
const [network, setNetwork] = useState(defaultNetwork);
|
|
3071
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
3072
|
+
const [error, setError] = useState(null);
|
|
3073
|
+
const [quote, setQuote] = useState(null);
|
|
3074
|
+
const [widgetUrl, setWidgetUrl] = useState(null);
|
|
3075
|
+
const isDark = theme === "dark";
|
|
3076
|
+
const calculateQuote = useCallback(() => {
|
|
3077
|
+
const amount = parseFloat(cryptoAmount);
|
|
3078
|
+
if (isNaN(amount) || amount <= 0) return null;
|
|
3079
|
+
const cryptoRate = CRYPTO_RATES2[cryptoCurrency.toUpperCase()] || 1;
|
|
3080
|
+
const grossAmount = amount * cryptoRate;
|
|
3081
|
+
const providerFee = grossAmount * 0.025;
|
|
3082
|
+
const networkFee = cryptoCurrency === "ETH" ? 5 : 1;
|
|
3083
|
+
const totalFee = providerFee + networkFee;
|
|
3084
|
+
const netAmount = grossAmount - totalFee;
|
|
3085
|
+
return {
|
|
3086
|
+
cryptoCurrency,
|
|
3087
|
+
cryptoAmount: amount,
|
|
3088
|
+
fiatCurrency,
|
|
3089
|
+
fiatAmount: parseFloat(netAmount.toFixed(2)),
|
|
3090
|
+
network,
|
|
3091
|
+
rate: cryptoRate,
|
|
3092
|
+
fees: {
|
|
3093
|
+
network: networkFee,
|
|
3094
|
+
provider: providerFee,
|
|
3095
|
+
total: totalFee
|
|
3096
|
+
},
|
|
3097
|
+
estimatedTime: "1-3 business days"
|
|
3098
|
+
};
|
|
3099
|
+
}, [cryptoAmount, cryptoCurrency, fiatCurrency, network]);
|
|
3100
|
+
useEffect(() => {
|
|
3101
|
+
const newQuote = calculateQuote();
|
|
3102
|
+
setQuote(newQuote);
|
|
3103
|
+
if (newQuote) {
|
|
3104
|
+
onQuoteUpdate?.(newQuote);
|
|
3105
|
+
}
|
|
3106
|
+
}, [calculateQuote, onQuoteUpdate]);
|
|
3107
|
+
const buildWidgetUrl = useCallback(() => {
|
|
3108
|
+
if (!walletAddress) return null;
|
|
3109
|
+
const baseUrl = "https://buy.onramper.com";
|
|
3110
|
+
const params = new URLSearchParams();
|
|
3111
|
+
const apiKey = process.env.NEXT_PUBLIC_ONRAMPER_API_KEY || "";
|
|
3112
|
+
if (apiKey) {
|
|
3113
|
+
params.append("apiKey", apiKey);
|
|
3114
|
+
}
|
|
3115
|
+
params.append("wallets", `ETH:${walletAddress},MATIC:${walletAddress},BNB:${walletAddress}`);
|
|
3116
|
+
params.append(
|
|
3117
|
+
"networkWallets",
|
|
3118
|
+
`ethereum:${walletAddress},polygon:${walletAddress},arbitrum:${walletAddress},optimism:${walletAddress},base:${walletAddress},bsc:${walletAddress}`
|
|
3119
|
+
);
|
|
3120
|
+
params.append("mode", "sell");
|
|
3121
|
+
params.append("defaultCrypto", cryptoCurrency);
|
|
3122
|
+
params.append("defaultFiat", fiatCurrency);
|
|
3123
|
+
if (cryptoAmount) {
|
|
3124
|
+
params.append("sellDefaultAmount", cryptoAmount);
|
|
3125
|
+
}
|
|
3126
|
+
if (network) {
|
|
3127
|
+
params.append("onlyCryptoNetworks", network);
|
|
3128
|
+
}
|
|
3129
|
+
if (email) params.append("email", email);
|
|
3130
|
+
if (country) params.append("country", country);
|
|
3131
|
+
params.append("color", accentColor.replace("#", ""));
|
|
3132
|
+
params.append("darkMode", isDark ? "true" : "false");
|
|
3133
|
+
params.append("hideTopBar", "false");
|
|
3134
|
+
params.append("isInAppBrowser", "true");
|
|
3135
|
+
params.append("partnerContext", `onesdk_sell_${Date.now()}`);
|
|
3136
|
+
return `${baseUrl}?${params.toString()}`;
|
|
3137
|
+
}, [walletAddress, cryptoCurrency, fiatCurrency, cryptoAmount, network, email, country, accentColor, isDark]);
|
|
3138
|
+
const handleSell = async () => {
|
|
3139
|
+
if (!walletAddress) {
|
|
3140
|
+
setError("Please connect your wallet first");
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
const amount = parseFloat(cryptoAmount);
|
|
3144
|
+
if (isNaN(amount) || amount <= 0) {
|
|
3145
|
+
setError("Please enter a valid amount");
|
|
3146
|
+
return;
|
|
3147
|
+
}
|
|
3148
|
+
if (balanceData && cryptoCurrency === "ETH") {
|
|
3149
|
+
const balance = parseFloat(balanceData.displayValue);
|
|
3150
|
+
if (amount > balance) {
|
|
3151
|
+
setError(`Insufficient balance. You have ${balance.toFixed(4)} ${cryptoCurrency}`);
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
setIsLoading(true);
|
|
3156
|
+
setError(null);
|
|
3157
|
+
try {
|
|
3158
|
+
const engineUrl = getEngineUrl();
|
|
3159
|
+
const response = await fetch(`${engineUrl}/v1/fiat/offramp`, {
|
|
3160
|
+
method: "POST",
|
|
3161
|
+
headers: { "Content-Type": "application/json" },
|
|
3162
|
+
body: JSON.stringify({
|
|
3163
|
+
walletAddress,
|
|
3164
|
+
cryptoCurrency,
|
|
3165
|
+
cryptoAmount: amount,
|
|
3166
|
+
fiatCurrency,
|
|
3167
|
+
network,
|
|
3168
|
+
email
|
|
3169
|
+
})
|
|
3170
|
+
});
|
|
3171
|
+
if (response.ok) {
|
|
3172
|
+
const data = await response.json();
|
|
3173
|
+
if (data.success && data.data?.widgetUrl) {
|
|
3174
|
+
setWidgetUrl(data.data.widgetUrl);
|
|
3175
|
+
if (mode === "popup") {
|
|
3176
|
+
window.open(data.data.widgetUrl, "_blank", "width=450,height=700");
|
|
3177
|
+
}
|
|
3178
|
+
return;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
const directUrl = buildWidgetUrl();
|
|
3182
|
+
if (directUrl) {
|
|
3183
|
+
setWidgetUrl(directUrl);
|
|
3184
|
+
if (mode === "popup") {
|
|
3185
|
+
window.open(directUrl, "_blank", "width=450,height=700");
|
|
3186
|
+
}
|
|
3187
|
+
} else {
|
|
3188
|
+
throw new Error("Failed to generate widget URL");
|
|
3189
|
+
}
|
|
3190
|
+
} catch (err) {
|
|
3191
|
+
const error2 = err instanceof Error ? err : new Error("Failed to start sale");
|
|
3192
|
+
setError(error2.message);
|
|
3193
|
+
onError?.(error2);
|
|
3194
|
+
} finally {
|
|
3195
|
+
setIsLoading(false);
|
|
3196
|
+
}
|
|
3197
|
+
};
|
|
3198
|
+
const handleUseMax = () => {
|
|
3199
|
+
if (balanceData && cryptoCurrency === "ETH") {
|
|
3200
|
+
const balance = parseFloat(balanceData.displayValue);
|
|
3201
|
+
const maxAmount = Math.max(0, balance - 5e-3);
|
|
3202
|
+
setCryptoAmount(maxAmount.toFixed(6));
|
|
3203
|
+
}
|
|
3204
|
+
};
|
|
3205
|
+
const handleCloseEmbed = () => {
|
|
3206
|
+
setWidgetUrl(null);
|
|
3207
|
+
onClose?.();
|
|
3208
|
+
};
|
|
3209
|
+
const bgColor = isDark ? "#1f2937" : "#ffffff";
|
|
3210
|
+
const borderColor = isDark ? "#374151" : "#e5e7eb";
|
|
3211
|
+
const textColor = isDark ? "#ffffff" : "#111827";
|
|
3212
|
+
const mutedColor = isDark ? "#9ca3af" : "#6b7280";
|
|
3213
|
+
const inputBg = isDark ? "#374151" : "#f3f4f6";
|
|
3214
|
+
const quoteBg = isDark ? "#374151" : "#f3f4f6";
|
|
3215
|
+
if (mode === "embed" && widgetUrl) {
|
|
3216
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { ...style }, children: [
|
|
3217
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "flex-end", marginBottom: "8px" }, children: /* @__PURE__ */ jsx(
|
|
3218
|
+
"button",
|
|
3219
|
+
{
|
|
3220
|
+
onClick: handleCloseEmbed,
|
|
3221
|
+
style: {
|
|
3222
|
+
background: "none",
|
|
3223
|
+
border: "none",
|
|
3224
|
+
color: mutedColor,
|
|
3225
|
+
cursor: "pointer",
|
|
3226
|
+
fontSize: "14px"
|
|
3227
|
+
},
|
|
3228
|
+
children: "Close"
|
|
3229
|
+
}
|
|
3230
|
+
) }),
|
|
3231
|
+
/* @__PURE__ */ jsx(
|
|
3232
|
+
"iframe",
|
|
3233
|
+
{
|
|
3234
|
+
src: widgetUrl,
|
|
3235
|
+
width: "100%",
|
|
3236
|
+
height: embedHeight,
|
|
3237
|
+
style: { border: "none", borderRadius: "16px" },
|
|
3238
|
+
allow: "payment; clipboard-read; clipboard-write"
|
|
3239
|
+
}
|
|
3240
|
+
)
|
|
3241
|
+
] });
|
|
3242
|
+
}
|
|
3243
|
+
return /* @__PURE__ */ jsxs(
|
|
3244
|
+
"div",
|
|
3245
|
+
{
|
|
3246
|
+
className,
|
|
3247
|
+
style: {
|
|
3248
|
+
...containerStyle3,
|
|
3249
|
+
backgroundColor: bgColor,
|
|
3250
|
+
borderColor,
|
|
3251
|
+
...style
|
|
3252
|
+
},
|
|
3253
|
+
children: [
|
|
3254
|
+
/* @__PURE__ */ jsxs("div", { style: headerStyle2, children: [
|
|
3255
|
+
/* @__PURE__ */ jsx("h3", { style: { color: textColor, margin: 0, fontSize: "18px", fontWeight: 600 }, children: "Sell Crypto" }),
|
|
3256
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor, fontSize: "12px" }, children: "Cash out to bank" })
|
|
3257
|
+
] }),
|
|
3258
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3259
|
+
/* @__PURE__ */ jsx("label", { style: { color: mutedColor, fontSize: "14px", marginBottom: "8px", display: "block" }, children: "You Sell" }),
|
|
3260
|
+
/* @__PURE__ */ jsxs("div", { style: rowStyle2, children: [
|
|
3261
|
+
/* @__PURE__ */ jsx(
|
|
3262
|
+
"input",
|
|
3263
|
+
{
|
|
3264
|
+
type: "number",
|
|
3265
|
+
value: cryptoAmount,
|
|
3266
|
+
onChange: (e) => setCryptoAmount(e.target.value),
|
|
3267
|
+
placeholder: "0.0",
|
|
3268
|
+
min: "0",
|
|
3269
|
+
step: "any",
|
|
3270
|
+
style: {
|
|
3271
|
+
...inputStyle3,
|
|
3272
|
+
flex: 1,
|
|
3273
|
+
backgroundColor: inputBg,
|
|
3274
|
+
border: `1px solid ${borderColor}`,
|
|
3275
|
+
color: textColor
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
),
|
|
3279
|
+
/* @__PURE__ */ jsx(
|
|
3280
|
+
"select",
|
|
3281
|
+
{
|
|
3282
|
+
value: cryptoCurrency,
|
|
3283
|
+
onChange: (e) => setCryptoCurrency(e.target.value),
|
|
3284
|
+
style: {
|
|
3285
|
+
...selectStyle2,
|
|
3286
|
+
backgroundColor: inputBg,
|
|
3287
|
+
border: `1px solid ${borderColor}`,
|
|
3288
|
+
color: textColor,
|
|
3289
|
+
minWidth: "100px",
|
|
3290
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3291
|
+
backgroundSize: "16px"
|
|
3292
|
+
},
|
|
3293
|
+
children: supportedCryptos.map((crypto) => /* @__PURE__ */ jsx("option", { value: crypto, children: crypto }, crypto))
|
|
3294
|
+
}
|
|
3295
|
+
)
|
|
3296
|
+
] }),
|
|
3297
|
+
balanceData && cryptoCurrency === "ETH" && /* @__PURE__ */ jsxs("div", { style: balanceStyle, children: [
|
|
3298
|
+
/* @__PURE__ */ jsxs("span", { style: { color: mutedColor }, children: [
|
|
3299
|
+
"Balance: ",
|
|
3300
|
+
parseFloat(balanceData.displayValue).toFixed(4),
|
|
3301
|
+
" ETH"
|
|
3302
|
+
] }),
|
|
3303
|
+
/* @__PURE__ */ jsx(
|
|
3304
|
+
"button",
|
|
3305
|
+
{
|
|
3306
|
+
onClick: handleUseMax,
|
|
3307
|
+
style: {
|
|
3308
|
+
background: "none",
|
|
3309
|
+
border: "none",
|
|
3310
|
+
color: accentColor,
|
|
3311
|
+
cursor: "pointer",
|
|
3312
|
+
fontSize: "12px",
|
|
3313
|
+
padding: 0
|
|
3314
|
+
},
|
|
3315
|
+
children: "Use Max"
|
|
3316
|
+
}
|
|
3317
|
+
)
|
|
3318
|
+
] })
|
|
3319
|
+
] }),
|
|
3320
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3321
|
+
/* @__PURE__ */ jsx("label", { style: { color: mutedColor, fontSize: "14px", marginBottom: "8px", display: "block" }, children: "Network" }),
|
|
3322
|
+
/* @__PURE__ */ jsx(
|
|
3323
|
+
"select",
|
|
3324
|
+
{
|
|
3325
|
+
value: network,
|
|
3326
|
+
onChange: (e) => setNetwork(e.target.value),
|
|
3327
|
+
style: {
|
|
3328
|
+
...selectStyle2,
|
|
3329
|
+
width: "100%",
|
|
3330
|
+
backgroundColor: inputBg,
|
|
3331
|
+
border: `1px solid ${borderColor}`,
|
|
3332
|
+
color: textColor,
|
|
3333
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3334
|
+
backgroundSize: "16px"
|
|
3335
|
+
},
|
|
3336
|
+
children: supportedNetworks.map((net) => /* @__PURE__ */ jsx("option", { value: net, children: NETWORK_DISPLAY_NAMES2[net] || net }, net))
|
|
3337
|
+
}
|
|
3338
|
+
)
|
|
3339
|
+
] }),
|
|
3340
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3341
|
+
/* @__PURE__ */ jsx("label", { style: { color: mutedColor, fontSize: "14px", marginBottom: "8px", display: "block" }, children: "You Receive" }),
|
|
3342
|
+
/* @__PURE__ */ jsxs("div", { style: rowStyle2, children: [
|
|
3343
|
+
/* @__PURE__ */ jsx(
|
|
3344
|
+
"div",
|
|
3345
|
+
{
|
|
3346
|
+
style: {
|
|
3347
|
+
...inputStyle3,
|
|
3348
|
+
flex: 1,
|
|
3349
|
+
backgroundColor: inputBg,
|
|
3350
|
+
border: `1px solid ${borderColor}`,
|
|
3351
|
+
color: textColor,
|
|
3352
|
+
display: "flex",
|
|
3353
|
+
alignItems: "center"
|
|
3354
|
+
},
|
|
3355
|
+
children: /* @__PURE__ */ jsx("span", { style: { color: quote ? textColor : mutedColor }, children: quote ? `~$${quote.fiatAmount.toLocaleString()}` : "$0.00" })
|
|
3356
|
+
}
|
|
3357
|
+
),
|
|
3358
|
+
/* @__PURE__ */ jsx(
|
|
3359
|
+
"select",
|
|
3360
|
+
{
|
|
3361
|
+
value: fiatCurrency,
|
|
3362
|
+
onChange: (e) => setFiatCurrency(e.target.value),
|
|
3363
|
+
style: {
|
|
3364
|
+
...selectStyle2,
|
|
3365
|
+
backgroundColor: inputBg,
|
|
3366
|
+
border: `1px solid ${borderColor}`,
|
|
3367
|
+
color: textColor,
|
|
3368
|
+
minWidth: "100px",
|
|
3369
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3370
|
+
backgroundSize: "16px"
|
|
3371
|
+
},
|
|
3372
|
+
children: supportedFiats.map((fiat) => /* @__PURE__ */ jsx("option", { value: fiat, children: fiat }, fiat))
|
|
3373
|
+
}
|
|
3374
|
+
)
|
|
3375
|
+
] })
|
|
3376
|
+
] }),
|
|
3377
|
+
quote && /* @__PURE__ */ jsxs("div", { style: { ...quoteBoxStyle2, backgroundColor: quoteBg }, children: [
|
|
3378
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
|
|
3379
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Rate" }),
|
|
3380
|
+
/* @__PURE__ */ jsxs("span", { style: { color: textColor }, children: [
|
|
3381
|
+
"1 ",
|
|
3382
|
+
cryptoCurrency,
|
|
3383
|
+
" = $",
|
|
3384
|
+
quote.rate.toLocaleString()
|
|
3385
|
+
] })
|
|
3386
|
+
] }),
|
|
3387
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px" }, children: [
|
|
3388
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Fees" }),
|
|
3389
|
+
/* @__PURE__ */ jsxs("span", { style: { color: textColor }, children: [
|
|
3390
|
+
"~$",
|
|
3391
|
+
quote.fees.total.toFixed(2)
|
|
3392
|
+
] })
|
|
3393
|
+
] }),
|
|
3394
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
3395
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Est. Arrival" }),
|
|
3396
|
+
/* @__PURE__ */ jsx("span", { style: { color: textColor }, children: quote.estimatedTime })
|
|
3397
|
+
] })
|
|
3398
|
+
] }),
|
|
3399
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
3400
|
+
padding: "12px",
|
|
3401
|
+
backgroundColor: isDark ? "rgba(251, 191, 36, 0.1)" : "rgba(251, 191, 36, 0.15)",
|
|
3402
|
+
borderRadius: "8px",
|
|
3403
|
+
fontSize: "12px",
|
|
3404
|
+
color: "#fbbf24"
|
|
3405
|
+
}, children: "Bank transfers typically take 1-3 business days. KYC verification may be required." }),
|
|
3406
|
+
error && /* @__PURE__ */ jsx("div", { style: {
|
|
3407
|
+
color: "#ef4444",
|
|
3408
|
+
fontSize: "14px",
|
|
3409
|
+
padding: "12px",
|
|
3410
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
3411
|
+
borderRadius: "8px"
|
|
3412
|
+
}, children: error }),
|
|
3413
|
+
/* @__PURE__ */ jsx(
|
|
3414
|
+
"button",
|
|
3415
|
+
{
|
|
3416
|
+
onClick: handleSell,
|
|
3417
|
+
disabled: isLoading || !walletAddress,
|
|
3418
|
+
style: {
|
|
3419
|
+
...buttonStyle3,
|
|
3420
|
+
backgroundColor: isLoading || !walletAddress ? "#6b7280" : accentColor,
|
|
3421
|
+
color: "#ffffff",
|
|
3422
|
+
cursor: isLoading || !walletAddress ? "not-allowed" : "pointer"
|
|
3423
|
+
},
|
|
3424
|
+
children: isLoading ? "Loading..." : !walletAddress ? "Connect Wallet" : `Sell ${cryptoCurrency}`
|
|
3425
|
+
}
|
|
3426
|
+
),
|
|
3427
|
+
walletAddress && /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", color: mutedColor, fontSize: "12px" }, children: [
|
|
3428
|
+
"Selling from: ",
|
|
3429
|
+
walletAddress.slice(0, 6),
|
|
3430
|
+
"...",
|
|
3431
|
+
walletAddress.slice(-4)
|
|
3432
|
+
] })
|
|
3433
|
+
]
|
|
3434
|
+
}
|
|
3435
|
+
);
|
|
3436
|
+
}
|
|
3437
|
+
function OneSellUSDTWidget(props) {
|
|
3438
|
+
return /* @__PURE__ */ jsx(OneOfframpWidget, { ...props, defaultCrypto: "USDT" });
|
|
3439
|
+
}
|
|
3440
|
+
function OneSellUSDCWidget(props) {
|
|
3441
|
+
return /* @__PURE__ */ jsx(OneOfframpWidget, { ...props, defaultCrypto: "USDC" });
|
|
3442
|
+
}
|
|
3443
|
+
function OneSellETHWidget(props) {
|
|
3444
|
+
return /* @__PURE__ */ jsx(OneOfframpWidget, { ...props, defaultCrypto: "ETH" });
|
|
3445
|
+
}
|
|
3446
|
+
var CHAIN_CONFIGS2 = [
|
|
3447
|
+
{ chain: ethereum, name: "Ethereum", shortName: "ETH", nativeToken: "ETH" },
|
|
3448
|
+
{ chain: base, name: "Base", shortName: "BASE", nativeToken: "ETH" },
|
|
3449
|
+
{ chain: arbitrum, name: "Arbitrum", shortName: "ARB", nativeToken: "ETH" },
|
|
3450
|
+
{ chain: optimism, name: "Optimism", shortName: "OP", nativeToken: "ETH" },
|
|
3451
|
+
{ chain: polygon, name: "Polygon", shortName: "MATIC", nativeToken: "POL" },
|
|
3452
|
+
{ chain: bsc, name: "BNB Chain", shortName: "BSC", nativeToken: "BNB" },
|
|
3453
|
+
{ chain: avalanche, name: "Avalanche", shortName: "AVAX", nativeToken: "AVAX" }
|
|
3454
|
+
];
|
|
3455
|
+
var TOKENS_BY_CHAIN = {
|
|
3456
|
+
// Ethereum
|
|
3457
|
+
1: [
|
|
3458
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "ETH", name: "Ethereum", decimals: 18, chainId: 1 },
|
|
3459
|
+
{ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", symbol: "USDC", name: "USD Coin", decimals: 6, chainId: 1 },
|
|
3460
|
+
{ address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", symbol: "USDT", name: "Tether", decimals: 6, chainId: 1 },
|
|
3461
|
+
{ address: "0x6B175474E89094C44Da98b954EescdeCB5", symbol: "DAI", name: "Dai", decimals: 18, chainId: 1 },
|
|
3462
|
+
{ address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", symbol: "WETH", name: "Wrapped Ether", decimals: 18, chainId: 1 }
|
|
3463
|
+
],
|
|
3464
|
+
// Base
|
|
3465
|
+
8453: [
|
|
3466
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "ETH", name: "Ethereum", decimals: 18, chainId: 8453 },
|
|
3467
|
+
{ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", name: "USD Coin", decimals: 6, chainId: 8453 },
|
|
3468
|
+
{ address: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", symbol: "DAI", name: "Dai", decimals: 18, chainId: 8453 },
|
|
3469
|
+
{ address: "0x4200000000000000000000000000000000000006", symbol: "WETH", name: "Wrapped Ether", decimals: 18, chainId: 8453 }
|
|
3470
|
+
],
|
|
3471
|
+
// Arbitrum
|
|
3472
|
+
42161: [
|
|
3473
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "ETH", name: "Ethereum", decimals: 18, chainId: 42161 },
|
|
3474
|
+
{ address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", symbol: "USDC", name: "USD Coin", decimals: 6, chainId: 42161 },
|
|
3475
|
+
{ address: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9", symbol: "USDT", name: "Tether", decimals: 6, chainId: 42161 },
|
|
3476
|
+
{ address: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", symbol: "WETH", name: "Wrapped Ether", decimals: 18, chainId: 42161 }
|
|
3477
|
+
],
|
|
3478
|
+
// Optimism
|
|
3479
|
+
10: [
|
|
3480
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "ETH", name: "Ethereum", decimals: 18, chainId: 10 },
|
|
3481
|
+
{ address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85", symbol: "USDC", name: "USD Coin", decimals: 6, chainId: 10 },
|
|
3482
|
+
{ address: "0x94b008aA00579c1307B0EF2c499aD98a8ce58e58", symbol: "USDT", name: "Tether", decimals: 6, chainId: 10 },
|
|
3483
|
+
{ address: "0x4200000000000000000000000000000000000006", symbol: "WETH", name: "Wrapped Ether", decimals: 18, chainId: 10 }
|
|
3484
|
+
],
|
|
3485
|
+
// Polygon
|
|
3486
|
+
137: [
|
|
3487
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "POL", name: "Polygon", decimals: 18, chainId: 137 },
|
|
3488
|
+
{ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", symbol: "USDC", name: "USD Coin", decimals: 6, chainId: 137 },
|
|
3489
|
+
{ address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", symbol: "USDT", name: "Tether", decimals: 6, chainId: 137 },
|
|
3490
|
+
{ address: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", symbol: "WETH", name: "Wrapped Ether", decimals: 18, chainId: 137 }
|
|
3491
|
+
],
|
|
3492
|
+
// BSC
|
|
3493
|
+
56: [
|
|
3494
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "BNB", name: "BNB", decimals: 18, chainId: 56 },
|
|
3495
|
+
{ address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", symbol: "USDC", name: "USD Coin", decimals: 18, chainId: 56 },
|
|
3496
|
+
{ address: "0x55d398326f99059fF775485246999027B3197955", symbol: "USDT", name: "Tether", decimals: 18, chainId: 56 },
|
|
3497
|
+
{ address: "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", symbol: "ETH", name: "Ethereum", decimals: 18, chainId: 56 }
|
|
3498
|
+
],
|
|
3499
|
+
// Avalanche
|
|
3500
|
+
43114: [
|
|
3501
|
+
{ address: "0x0000000000000000000000000000000000000000", symbol: "AVAX", name: "Avalanche", decimals: 18, chainId: 43114 },
|
|
3502
|
+
{ address: "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E", symbol: "USDC", name: "USD Coin", decimals: 6, chainId: 43114 },
|
|
3503
|
+
{ address: "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7", symbol: "USDT", name: "Tether", decimals: 6, chainId: 43114 },
|
|
3504
|
+
{ address: "0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB", symbol: "WETH", name: "Wrapped Ether", decimals: 18, chainId: 43114 }
|
|
3505
|
+
]
|
|
3506
|
+
};
|
|
3507
|
+
var containerStyle4 = {
|
|
3508
|
+
display: "flex",
|
|
3509
|
+
flexDirection: "column",
|
|
3510
|
+
gap: "16px",
|
|
3511
|
+
padding: "24px",
|
|
3512
|
+
borderRadius: "16px",
|
|
3513
|
+
border: "1px solid",
|
|
3514
|
+
maxWidth: "420px"
|
|
3515
|
+
};
|
|
3516
|
+
var chainSelectorStyle = {
|
|
3517
|
+
display: "flex",
|
|
3518
|
+
gap: "8px",
|
|
3519
|
+
alignItems: "center"
|
|
3520
|
+
};
|
|
3521
|
+
var tokenInputStyle = {
|
|
3522
|
+
display: "flex",
|
|
3523
|
+
flexDirection: "column",
|
|
3524
|
+
gap: "8px",
|
|
3525
|
+
padding: "16px",
|
|
3526
|
+
borderRadius: "12px"
|
|
3527
|
+
};
|
|
3528
|
+
var inputStyle4 = {
|
|
3529
|
+
width: "100%",
|
|
3530
|
+
padding: "8px 0",
|
|
3531
|
+
backgroundColor: "transparent",
|
|
3532
|
+
border: "none",
|
|
3533
|
+
fontSize: "24px",
|
|
3534
|
+
fontWeight: 600,
|
|
3535
|
+
outline: "none"
|
|
3536
|
+
};
|
|
3537
|
+
var selectStyle3 = {
|
|
3538
|
+
padding: "8px 12px",
|
|
3539
|
+
border: "none",
|
|
3540
|
+
borderRadius: "8px",
|
|
3541
|
+
fontSize: "14px",
|
|
3542
|
+
fontWeight: 500,
|
|
3543
|
+
cursor: "pointer",
|
|
3544
|
+
appearance: "none",
|
|
3545
|
+
backgroundRepeat: "no-repeat",
|
|
3546
|
+
backgroundPosition: "right 8px center",
|
|
3547
|
+
paddingRight: "28px"
|
|
3548
|
+
};
|
|
3549
|
+
var buttonStyle4 = {
|
|
3550
|
+
width: "100%",
|
|
3551
|
+
padding: "16px",
|
|
3552
|
+
border: "none",
|
|
3553
|
+
borderRadius: "12px",
|
|
3554
|
+
fontSize: "16px",
|
|
3555
|
+
fontWeight: 600,
|
|
3556
|
+
cursor: "pointer",
|
|
3557
|
+
transition: "background-color 0.2s"
|
|
3558
|
+
};
|
|
3559
|
+
var routeBoxStyle = {
|
|
3560
|
+
padding: "12px",
|
|
3561
|
+
borderRadius: "8px",
|
|
3562
|
+
fontSize: "13px"
|
|
3563
|
+
};
|
|
3564
|
+
var labelStyle2 = {
|
|
3565
|
+
fontSize: "12px",
|
|
3566
|
+
marginBottom: "4px"
|
|
3567
|
+
};
|
|
3568
|
+
function OneSwapWidget({
|
|
3569
|
+
defaultFromToken,
|
|
3570
|
+
defaultToToken,
|
|
3571
|
+
defaultFromChain = base,
|
|
3572
|
+
defaultToChain,
|
|
3573
|
+
supportedChains,
|
|
3574
|
+
tokens,
|
|
3575
|
+
mode = "auto",
|
|
3576
|
+
theme = "dark",
|
|
3577
|
+
accentColor = "#10b981",
|
|
3578
|
+
className,
|
|
3579
|
+
style,
|
|
3580
|
+
quoteEndpoint,
|
|
3581
|
+
executeEndpoint,
|
|
3582
|
+
onSwapSuccess,
|
|
3583
|
+
onSwapError,
|
|
3584
|
+
onQuoteReceived,
|
|
3585
|
+
onChainChange
|
|
3586
|
+
}) {
|
|
3587
|
+
const client = useThirdwebClient();
|
|
3588
|
+
const account = useActiveAccount();
|
|
3589
|
+
const { mutate: sendTransaction, isPending } = useSendTransaction();
|
|
3590
|
+
const availableChains = useMemo(() => {
|
|
3591
|
+
if (supportedChains) {
|
|
3592
|
+
return CHAIN_CONFIGS2.filter((c) => supportedChains.some((sc) => sc.id === c.chain.id));
|
|
3593
|
+
}
|
|
3594
|
+
return CHAIN_CONFIGS2;
|
|
3595
|
+
}, [supportedChains]);
|
|
3596
|
+
const [fromChain, setFromChain] = useState(
|
|
3597
|
+
availableChains.find((c) => c.chain.id === defaultFromChain.id) || availableChains[0]
|
|
3598
|
+
);
|
|
3599
|
+
const [toChain, setToChain] = useState(
|
|
3600
|
+
defaultToChain ? availableChains.find((c) => c.chain.id === defaultToChain.id) || availableChains[0] : fromChain
|
|
3601
|
+
);
|
|
3602
|
+
const fromTokens = useMemo(() => {
|
|
3603
|
+
if (tokens) {
|
|
3604
|
+
return tokens.filter((t) => t.chainId === fromChain.chain.id);
|
|
3605
|
+
}
|
|
3606
|
+
return TOKENS_BY_CHAIN[fromChain.chain.id] || [];
|
|
3607
|
+
}, [tokens, fromChain]);
|
|
3608
|
+
const toTokens = useMemo(() => {
|
|
3609
|
+
if (tokens) {
|
|
3610
|
+
return tokens.filter((t) => t.chainId === toChain.chain.id);
|
|
3611
|
+
}
|
|
3612
|
+
return TOKENS_BY_CHAIN[toChain.chain.id] || [];
|
|
3613
|
+
}, [tokens, toChain]);
|
|
3614
|
+
const [fromToken, setFromToken] = useState(defaultFromToken || fromTokens[0]);
|
|
3615
|
+
const [toToken, setToToken] = useState(defaultToToken || toTokens[1] || toTokens[0]);
|
|
3616
|
+
const [fromAmount, setFromAmount] = useState("");
|
|
3617
|
+
const [toAmount, setToAmount] = useState("");
|
|
3618
|
+
const [route, setRoute] = useState(null);
|
|
3619
|
+
const [isLoadingQuote, setIsLoadingQuote] = useState(false);
|
|
3620
|
+
const [error, setError] = useState(null);
|
|
3621
|
+
const isDark = theme === "dark";
|
|
3622
|
+
const isCrossChain = fromChain.chain.id !== toChain.chain.id;
|
|
3623
|
+
useEffect(() => {
|
|
3624
|
+
const newFromTokens = TOKENS_BY_CHAIN[fromChain.chain.id] || [];
|
|
3625
|
+
if (newFromTokens.length > 0 && !newFromTokens.some((t) => t.address === fromToken?.address)) {
|
|
3626
|
+
setFromToken(newFromTokens[0]);
|
|
3627
|
+
}
|
|
3628
|
+
}, [fromChain, fromToken?.address]);
|
|
3629
|
+
useEffect(() => {
|
|
3630
|
+
const newToTokens = TOKENS_BY_CHAIN[toChain.chain.id] || [];
|
|
3631
|
+
if (newToTokens.length > 0 && !newToTokens.some((t) => t.address === toToken?.address)) {
|
|
3632
|
+
const sameSymbol = newToTokens.find((t) => t.symbol === fromToken?.symbol);
|
|
3633
|
+
setToToken(sameSymbol || newToTokens[0]);
|
|
3634
|
+
}
|
|
3635
|
+
}, [toChain, toToken?.address, fromToken?.symbol]);
|
|
3636
|
+
useEffect(() => {
|
|
3637
|
+
onChainChange?.(fromChain.chain.id, toChain.chain.id);
|
|
3638
|
+
}, [fromChain, toChain, onChainChange]);
|
|
3639
|
+
const fetchQuote = useCallback(async () => {
|
|
3640
|
+
if (!fromAmount || parseFloat(fromAmount) <= 0 || !fromToken || !toToken) {
|
|
3641
|
+
setToAmount("");
|
|
3642
|
+
setRoute(null);
|
|
3643
|
+
return;
|
|
3644
|
+
}
|
|
3645
|
+
setIsLoadingQuote(true);
|
|
3646
|
+
setError(null);
|
|
3647
|
+
try {
|
|
3648
|
+
const engineUrl = getEngineUrl();
|
|
3649
|
+
const endpoint = quoteEndpoint || `${engineUrl}/v1/swap/quote`;
|
|
3650
|
+
const response = await fetch(endpoint, {
|
|
3651
|
+
method: "POST",
|
|
3652
|
+
headers: { "Content-Type": "application/json" },
|
|
3653
|
+
body: JSON.stringify({
|
|
3654
|
+
fromChainId: fromChain.chain.id,
|
|
3655
|
+
toChainId: toChain.chain.id,
|
|
3656
|
+
fromToken: fromToken.address,
|
|
3657
|
+
toToken: toToken.address,
|
|
3658
|
+
fromAmount,
|
|
3659
|
+
fromDecimals: fromToken.decimals,
|
|
3660
|
+
walletAddress: account?.address,
|
|
3661
|
+
slippage: 0.5
|
|
3662
|
+
// 0.5% default slippage
|
|
3663
|
+
})
|
|
3664
|
+
});
|
|
3665
|
+
const data = await response.json();
|
|
3666
|
+
if (data.success && data.data) {
|
|
3667
|
+
const routeData = {
|
|
3668
|
+
provider: data.data.provider || "aggregator",
|
|
3669
|
+
fromChain: fromChain.chain.id,
|
|
3670
|
+
toChain: toChain.chain.id,
|
|
3671
|
+
fromToken,
|
|
3672
|
+
toToken,
|
|
3673
|
+
fromAmount,
|
|
3674
|
+
toAmount: data.data.toAmount || "0",
|
|
3675
|
+
estimatedGas: data.data.estimatedGas || "0",
|
|
3676
|
+
priceImpact: data.data.priceImpact || "0",
|
|
3677
|
+
executionTime: isCrossChain ? "2-5 min" : "~30 sec",
|
|
3678
|
+
steps: data.data.steps || []
|
|
3679
|
+
};
|
|
3680
|
+
setRoute(routeData);
|
|
3681
|
+
setToAmount(routeData.toAmount);
|
|
3682
|
+
onQuoteReceived?.(routeData);
|
|
3683
|
+
} else {
|
|
3684
|
+
const estimatedOutput = estimateSwapOutput(fromAmount, fromToken, toToken);
|
|
3685
|
+
setToAmount(estimatedOutput.toFixed(6));
|
|
3686
|
+
setError(data.error?.message || null);
|
|
3687
|
+
}
|
|
3688
|
+
} catch (err) {
|
|
3689
|
+
const estimatedOutput = estimateSwapOutput(fromAmount, fromToken, toToken);
|
|
3690
|
+
setToAmount(estimatedOutput.toFixed(6));
|
|
3691
|
+
console.error("Quote fetch error:", err);
|
|
3692
|
+
} finally {
|
|
3693
|
+
setIsLoadingQuote(false);
|
|
3694
|
+
}
|
|
3695
|
+
}, [fromAmount, fromToken, toToken, fromChain, toChain, account?.address, quoteEndpoint, isCrossChain, onQuoteReceived]);
|
|
3696
|
+
const estimateSwapOutput = (amount, from, to) => {
|
|
3697
|
+
const prices = {
|
|
3698
|
+
ETH: 3500,
|
|
3699
|
+
WETH: 3500,
|
|
3700
|
+
BNB: 650,
|
|
3701
|
+
AVAX: 42,
|
|
3702
|
+
POL: 0.85,
|
|
3703
|
+
USDC: 1,
|
|
3704
|
+
USDT: 1,
|
|
3705
|
+
DAI: 1
|
|
3706
|
+
};
|
|
3707
|
+
const fromPrice = prices[from.symbol] || 1;
|
|
3708
|
+
const toPrice = prices[to.symbol] || 1;
|
|
3709
|
+
return parseFloat(amount) * fromPrice / toPrice;
|
|
3710
|
+
};
|
|
3711
|
+
useEffect(() => {
|
|
3712
|
+
const debounce = setTimeout(fetchQuote, 500);
|
|
3713
|
+
return () => clearTimeout(debounce);
|
|
3714
|
+
}, [fetchQuote]);
|
|
3715
|
+
const handleSwapDirection = () => {
|
|
3716
|
+
const tempChain = fromChain;
|
|
3717
|
+
const tempToken = fromToken;
|
|
3718
|
+
setFromChain(toChain);
|
|
3719
|
+
setToChain(tempChain);
|
|
3720
|
+
setFromToken(toToken);
|
|
3721
|
+
setToToken(tempToken);
|
|
3722
|
+
setFromAmount(toAmount);
|
|
3723
|
+
setToAmount(fromAmount);
|
|
3724
|
+
};
|
|
3725
|
+
const handleSwap = async () => {
|
|
3726
|
+
if (!account || !fromToken || !toToken) return;
|
|
3727
|
+
setError(null);
|
|
3728
|
+
try {
|
|
3729
|
+
const engineUrl = getEngineUrl();
|
|
3730
|
+
const endpoint = executeEndpoint || `${engineUrl}/v1/swap/execute`;
|
|
3731
|
+
const response = await fetch(endpoint, {
|
|
3732
|
+
method: "POST",
|
|
3733
|
+
headers: { "Content-Type": "application/json" },
|
|
3734
|
+
body: JSON.stringify({
|
|
3735
|
+
fromChainId: fromChain.chain.id,
|
|
3736
|
+
toChainId: toChain.chain.id,
|
|
3737
|
+
fromToken: fromToken.address,
|
|
3738
|
+
toToken: toToken.address,
|
|
3739
|
+
fromAmount,
|
|
3740
|
+
walletAddress: account.address,
|
|
3741
|
+
slippage: 0.5
|
|
3742
|
+
})
|
|
3743
|
+
});
|
|
3744
|
+
const data = await response.json();
|
|
3745
|
+
if (data.success && data.data?.transaction) {
|
|
3746
|
+
const tx = prepareTransaction({
|
|
3747
|
+
to: data.data.transaction.to,
|
|
3748
|
+
data: data.data.transaction.data,
|
|
3749
|
+
value: BigInt(data.data.transaction.value || 0),
|
|
3750
|
+
chain: fromChain.chain,
|
|
3751
|
+
client
|
|
3752
|
+
});
|
|
3753
|
+
sendTransaction(tx, {
|
|
3754
|
+
onSuccess: (result) => {
|
|
3755
|
+
onSwapSuccess?.(result.transactionHash, route || void 0);
|
|
3756
|
+
setFromAmount("");
|
|
3757
|
+
setToAmount("");
|
|
3758
|
+
setRoute(null);
|
|
3759
|
+
},
|
|
3760
|
+
onError: (err) => {
|
|
3761
|
+
setError(err.message);
|
|
3762
|
+
onSwapError?.(err);
|
|
3763
|
+
}
|
|
3764
|
+
});
|
|
3765
|
+
} else {
|
|
3766
|
+
throw new Error(data.error?.message || "Swap execution failed");
|
|
3767
|
+
}
|
|
3768
|
+
} catch (err) {
|
|
3769
|
+
const error2 = err instanceof Error ? err : new Error("Swap failed");
|
|
3770
|
+
setError(error2.message);
|
|
3771
|
+
onSwapError?.(error2);
|
|
3772
|
+
}
|
|
3773
|
+
};
|
|
3774
|
+
const canSwap = account && fromAmount && parseFloat(fromAmount) > 0 && !isPending && !isLoadingQuote;
|
|
3775
|
+
const bgColor = isDark ? "#1f2937" : "#ffffff";
|
|
3776
|
+
const borderColor = isDark ? "#374151" : "#e5e7eb";
|
|
3777
|
+
const textColor = isDark ? "#ffffff" : "#111827";
|
|
3778
|
+
const mutedColor = isDark ? "#9ca3af" : "#6b7280";
|
|
3779
|
+
const inputBg = isDark ? "#374151" : "#f3f4f6";
|
|
3780
|
+
return /* @__PURE__ */ jsxs(
|
|
3781
|
+
"div",
|
|
3782
|
+
{
|
|
3783
|
+
className,
|
|
3784
|
+
style: {
|
|
3785
|
+
...containerStyle4,
|
|
3786
|
+
backgroundColor: bgColor,
|
|
3787
|
+
borderColor,
|
|
3788
|
+
...style
|
|
3789
|
+
},
|
|
3790
|
+
children: [
|
|
3791
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
3792
|
+
/* @__PURE__ */ jsx("h3", { style: { color: textColor, margin: 0, fontSize: "18px", fontWeight: 600 }, children: "Swap" }),
|
|
3793
|
+
isCrossChain && /* @__PURE__ */ jsx("span", { style: {
|
|
3794
|
+
fontSize: "11px",
|
|
3795
|
+
padding: "4px 8px",
|
|
3796
|
+
backgroundColor: accentColor,
|
|
3797
|
+
color: "#fff",
|
|
3798
|
+
borderRadius: "4px"
|
|
3799
|
+
}, children: "Cross-Chain" })
|
|
3800
|
+
] }),
|
|
3801
|
+
/* @__PURE__ */ jsxs("div", { style: { ...tokenInputStyle, backgroundColor: inputBg }, children: [
|
|
3802
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
3803
|
+
/* @__PURE__ */ jsx("span", { style: { ...labelStyle2, color: mutedColor }, children: "From" }),
|
|
3804
|
+
mode !== "same-chain" && /* @__PURE__ */ jsx("div", { style: chainSelectorStyle, children: /* @__PURE__ */ jsx(
|
|
3805
|
+
"select",
|
|
3806
|
+
{
|
|
3807
|
+
value: fromChain.chain.id,
|
|
3808
|
+
onChange: (e) => {
|
|
3809
|
+
const chain = availableChains.find((c) => c.chain.id === parseInt(e.target.value));
|
|
3810
|
+
if (chain) setFromChain(chain);
|
|
3811
|
+
},
|
|
3812
|
+
style: {
|
|
3813
|
+
...selectStyle3,
|
|
3814
|
+
backgroundColor: isDark ? "#4b5563" : "#e5e7eb",
|
|
3815
|
+
color: textColor,
|
|
3816
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3817
|
+
backgroundSize: "12px",
|
|
3818
|
+
fontSize: "12px",
|
|
3819
|
+
padding: "6px 24px 6px 8px"
|
|
3820
|
+
},
|
|
3821
|
+
children: availableChains.map((c) => /* @__PURE__ */ jsx("option", { value: c.chain.id, children: c.shortName }, c.chain.id))
|
|
3822
|
+
}
|
|
3823
|
+
) })
|
|
3824
|
+
] }),
|
|
3825
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px", alignItems: "center" }, children: [
|
|
3826
|
+
/* @__PURE__ */ jsx(
|
|
3827
|
+
"input",
|
|
3828
|
+
{
|
|
3829
|
+
type: "number",
|
|
3830
|
+
value: fromAmount,
|
|
3831
|
+
onChange: (e) => setFromAmount(e.target.value),
|
|
3832
|
+
placeholder: "0.0",
|
|
3833
|
+
style: { ...inputStyle4, flex: 1, color: textColor }
|
|
3834
|
+
}
|
|
3835
|
+
),
|
|
3836
|
+
/* @__PURE__ */ jsx(
|
|
3837
|
+
"select",
|
|
3838
|
+
{
|
|
3839
|
+
value: fromToken?.address || "",
|
|
3840
|
+
onChange: (e) => {
|
|
3841
|
+
const token = fromTokens.find((t) => t.address === e.target.value);
|
|
3842
|
+
if (token) setFromToken(token);
|
|
3843
|
+
},
|
|
3844
|
+
style: {
|
|
3845
|
+
...selectStyle3,
|
|
3846
|
+
backgroundColor: isDark ? "#4b5563" : "#e5e7eb",
|
|
3847
|
+
color: textColor,
|
|
3848
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3849
|
+
backgroundSize: "12px"
|
|
3850
|
+
},
|
|
3851
|
+
children: fromTokens.map((token) => /* @__PURE__ */ jsx("option", { value: token.address, children: token.symbol }, token.address))
|
|
3852
|
+
}
|
|
3853
|
+
)
|
|
3854
|
+
] })
|
|
3855
|
+
] }),
|
|
3856
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", margin: "-8px 0" }, children: /* @__PURE__ */ jsx(
|
|
3857
|
+
"button",
|
|
3858
|
+
{
|
|
3859
|
+
onClick: handleSwapDirection,
|
|
3860
|
+
style: {
|
|
3861
|
+
width: "36px",
|
|
3862
|
+
height: "36px",
|
|
3863
|
+
borderRadius: "50%",
|
|
3864
|
+
backgroundColor: inputBg,
|
|
3865
|
+
border: `2px solid ${bgColor}`,
|
|
3866
|
+
cursor: "pointer",
|
|
3867
|
+
display: "flex",
|
|
3868
|
+
alignItems: "center",
|
|
3869
|
+
justifyContent: "center",
|
|
3870
|
+
fontSize: "16px",
|
|
3871
|
+
color: mutedColor,
|
|
3872
|
+
zIndex: 1
|
|
3873
|
+
},
|
|
3874
|
+
children: "\u2195"
|
|
3875
|
+
}
|
|
3876
|
+
) }),
|
|
3877
|
+
/* @__PURE__ */ jsxs("div", { style: { ...tokenInputStyle, backgroundColor: inputBg }, children: [
|
|
3878
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
|
|
3879
|
+
/* @__PURE__ */ jsx("span", { style: { ...labelStyle2, color: mutedColor }, children: "To" }),
|
|
3880
|
+
mode !== "same-chain" && /* @__PURE__ */ jsx("div", { style: chainSelectorStyle, children: /* @__PURE__ */ jsx(
|
|
3881
|
+
"select",
|
|
3882
|
+
{
|
|
3883
|
+
value: toChain.chain.id,
|
|
3884
|
+
onChange: (e) => {
|
|
3885
|
+
const chain = availableChains.find((c) => c.chain.id === parseInt(e.target.value));
|
|
3886
|
+
if (chain) setToChain(chain);
|
|
3887
|
+
},
|
|
3888
|
+
style: {
|
|
3889
|
+
...selectStyle3,
|
|
3890
|
+
backgroundColor: isDark ? "#4b5563" : "#e5e7eb",
|
|
3891
|
+
color: textColor,
|
|
3892
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3893
|
+
backgroundSize: "12px",
|
|
3894
|
+
fontSize: "12px",
|
|
3895
|
+
padding: "6px 24px 6px 8px"
|
|
3896
|
+
},
|
|
3897
|
+
children: availableChains.map((c) => /* @__PURE__ */ jsx("option", { value: c.chain.id, children: c.shortName }, c.chain.id))
|
|
3898
|
+
}
|
|
3899
|
+
) })
|
|
3900
|
+
] }),
|
|
3901
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px", alignItems: "center" }, children: [
|
|
3902
|
+
/* @__PURE__ */ jsx(
|
|
3903
|
+
"input",
|
|
3904
|
+
{
|
|
3905
|
+
type: "number",
|
|
3906
|
+
value: toAmount,
|
|
3907
|
+
placeholder: "0.0",
|
|
3908
|
+
readOnly: true,
|
|
3909
|
+
style: { ...inputStyle4, flex: 1, color: mutedColor }
|
|
3910
|
+
}
|
|
3911
|
+
),
|
|
3912
|
+
/* @__PURE__ */ jsx(
|
|
3913
|
+
"select",
|
|
3914
|
+
{
|
|
3915
|
+
value: toToken?.address || "",
|
|
3916
|
+
onChange: (e) => {
|
|
3917
|
+
const token = toTokens.find((t) => t.address === e.target.value);
|
|
3918
|
+
if (token) setToToken(token);
|
|
3919
|
+
},
|
|
3920
|
+
style: {
|
|
3921
|
+
...selectStyle3,
|
|
3922
|
+
backgroundColor: isDark ? "#4b5563" : "#e5e7eb",
|
|
3923
|
+
color: textColor,
|
|
3924
|
+
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='${isDark ? "%239ca3af" : "%236b7280"}'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E")`,
|
|
3925
|
+
backgroundSize: "12px"
|
|
3926
|
+
},
|
|
3927
|
+
children: toTokens.map((token) => /* @__PURE__ */ jsx("option", { value: token.address, children: token.symbol }, token.address))
|
|
3928
|
+
}
|
|
3929
|
+
)
|
|
3930
|
+
] })
|
|
3931
|
+
] }),
|
|
3932
|
+
(route || fromAmount && toAmount) && /* @__PURE__ */ jsxs("div", { style: { ...routeBoxStyle, backgroundColor: inputBg }, children: [
|
|
3933
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "6px" }, children: [
|
|
3934
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Rate" }),
|
|
3935
|
+
/* @__PURE__ */ jsxs("span", { style: { color: textColor }, children: [
|
|
3936
|
+
"1 ",
|
|
3937
|
+
fromToken?.symbol,
|
|
3938
|
+
" = ",
|
|
3939
|
+
toAmount && fromAmount ? (parseFloat(toAmount) / parseFloat(fromAmount)).toFixed(6) : "0",
|
|
3940
|
+
" ",
|
|
3941
|
+
toToken?.symbol
|
|
3942
|
+
] })
|
|
3943
|
+
] }),
|
|
3944
|
+
route?.priceImpact && parseFloat(route.priceImpact) > 0 && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "6px" }, children: [
|
|
3945
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Price Impact" }),
|
|
3946
|
+
/* @__PURE__ */ jsxs("span", { style: { color: parseFloat(route.priceImpact) > 3 ? "#ef4444" : textColor }, children: [
|
|
3947
|
+
route.priceImpact,
|
|
3948
|
+
"%"
|
|
3949
|
+
] })
|
|
3950
|
+
] }),
|
|
3951
|
+
isCrossChain && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
|
|
3952
|
+
/* @__PURE__ */ jsx("span", { style: { color: mutedColor }, children: "Est. Time" }),
|
|
3953
|
+
/* @__PURE__ */ jsx("span", { style: { color: textColor }, children: route?.executionTime || "2-5 min" })
|
|
3954
|
+
] })
|
|
3955
|
+
] }),
|
|
3956
|
+
error && /* @__PURE__ */ jsx("div", { style: {
|
|
3957
|
+
color: "#ef4444",
|
|
3958
|
+
fontSize: "14px",
|
|
3959
|
+
padding: "10px 12px",
|
|
3960
|
+
backgroundColor: "rgba(239, 68, 68, 0.1)",
|
|
3961
|
+
borderRadius: "8px"
|
|
3962
|
+
}, children: error }),
|
|
3963
|
+
/* @__PURE__ */ jsx(
|
|
3964
|
+
"button",
|
|
3965
|
+
{
|
|
3966
|
+
onClick: handleSwap,
|
|
3967
|
+
disabled: !canSwap,
|
|
3968
|
+
style: {
|
|
3969
|
+
...buttonStyle4,
|
|
3970
|
+
backgroundColor: canSwap ? accentColor : "#6b7280",
|
|
3971
|
+
color: "#ffffff",
|
|
3972
|
+
cursor: canSwap ? "pointer" : "not-allowed"
|
|
3973
|
+
},
|
|
3974
|
+
children: isPending ? "Swapping..." : isLoadingQuote ? "Getting Quote..." : !account ? "Connect Wallet" : isCrossChain ? `Bridge & Swap` : "Swap"
|
|
3975
|
+
}
|
|
3976
|
+
)
|
|
3977
|
+
]
|
|
3978
|
+
}
|
|
3979
|
+
);
|
|
3980
|
+
}
|
|
3981
|
+
function OneSameChainSwap(props) {
|
|
3982
|
+
return /* @__PURE__ */ jsx(OneSwapWidget, { ...props, mode: "same-chain" });
|
|
3983
|
+
}
|
|
3984
|
+
function OneCrossChainSwap(props) {
|
|
3985
|
+
return /* @__PURE__ */ jsx(OneSwapWidget, { ...props, mode: "cross-chain" });
|
|
3986
|
+
}
|
|
3987
|
+
var containerStyle5 = {
|
|
3988
|
+
display: "flex",
|
|
3989
|
+
flexDirection: "column",
|
|
3990
|
+
gap: "16px"
|
|
3991
|
+
};
|
|
3992
|
+
var balanceCardStyle = {
|
|
3993
|
+
padding: "24px",
|
|
3994
|
+
backgroundColor: "#1f2937",
|
|
3995
|
+
borderRadius: "16px",
|
|
3996
|
+
border: "1px solid #374151"
|
|
3997
|
+
};
|
|
3998
|
+
var tokenRowStyle = {
|
|
3999
|
+
display: "flex",
|
|
4000
|
+
alignItems: "center",
|
|
4001
|
+
justifyContent: "space-between",
|
|
4002
|
+
padding: "12px 16px",
|
|
4003
|
+
borderRadius: "12px",
|
|
4004
|
+
cursor: "pointer",
|
|
4005
|
+
transition: "background-color 0.2s"
|
|
4006
|
+
};
|
|
4007
|
+
var formatUSD = (value) => {
|
|
4008
|
+
return new Intl.NumberFormat("en-US", {
|
|
4009
|
+
style: "currency",
|
|
4010
|
+
currency: "USD",
|
|
4011
|
+
minimumFractionDigits: 2,
|
|
4012
|
+
maximumFractionDigits: 2
|
|
4013
|
+
}).format(value);
|
|
4014
|
+
};
|
|
4015
|
+
var formatBalance = (value, decimals = 4) => {
|
|
4016
|
+
const num = parseFloat(value);
|
|
4017
|
+
if (num === 0) return "0";
|
|
4018
|
+
if (num < 1e-4) return "<0.0001";
|
|
4019
|
+
return num.toFixed(decimals);
|
|
4020
|
+
};
|
|
4021
|
+
var CHAIN_INFO = {
|
|
4022
|
+
1: { name: "Ethereum", icon: "\u27E0" },
|
|
4023
|
+
8453: { name: "Base", icon: "\u{1F535}" },
|
|
4024
|
+
137: { name: "Polygon", icon: "\u{1F7E3}" },
|
|
4025
|
+
42161: { name: "Arbitrum", icon: "\u{1F537}" },
|
|
4026
|
+
10: { name: "Optimism", icon: "\u{1F534}" }
|
|
4027
|
+
};
|
|
4028
|
+
function OneWalletBalance({
|
|
4029
|
+
showTotalBalance = true,
|
|
4030
|
+
showTokenList = true,
|
|
4031
|
+
showChainFilter = true,
|
|
4032
|
+
showPriceChange = true,
|
|
4033
|
+
chains = [base, ethereum, polygon, arbitrum, optimism],
|
|
4034
|
+
balanceEndpoint = "/api/v1/assets",
|
|
4035
|
+
theme = "dark",
|
|
4036
|
+
className,
|
|
4037
|
+
style,
|
|
4038
|
+
compact = false,
|
|
4039
|
+
onTokenClick,
|
|
4040
|
+
onRefresh
|
|
4041
|
+
}) {
|
|
4042
|
+
useThirdwebClient();
|
|
4043
|
+
const account = useActiveAccount();
|
|
4044
|
+
const [tokens, setTokens] = useState([]);
|
|
4045
|
+
const [totalBalance, setTotalBalance] = useState(0);
|
|
4046
|
+
const [totalChange24h, setTotalChange24h] = useState(0);
|
|
4047
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
4048
|
+
const [selectedChain, setSelectedChain] = useState(null);
|
|
4049
|
+
const [error, setError] = useState(null);
|
|
4050
|
+
const fetchBalances = useCallback(async () => {
|
|
4051
|
+
if (!account?.address) return;
|
|
4052
|
+
setIsLoading(true);
|
|
4053
|
+
setError(null);
|
|
4054
|
+
try {
|
|
4055
|
+
const chainIds = chains.map((c) => c.id).join(",");
|
|
4056
|
+
const response = await fetch(`${balanceEndpoint}?address=${account.address}&chains=${chainIds}`);
|
|
4057
|
+
const data = await response.json();
|
|
4058
|
+
if (data.success && data.data) {
|
|
4059
|
+
const balanceData = data.data;
|
|
4060
|
+
setTokens(balanceData.tokens || []);
|
|
4061
|
+
setTotalBalance(balanceData.totalUsd || 0);
|
|
4062
|
+
setTotalChange24h(balanceData.change24hPercent || 0);
|
|
4063
|
+
} else {
|
|
4064
|
+
setError(data.error?.message || "Failed to fetch balances");
|
|
4065
|
+
}
|
|
4066
|
+
} catch (err) {
|
|
4067
|
+
setError("Failed to load balances");
|
|
4068
|
+
} finally {
|
|
4069
|
+
setIsLoading(false);
|
|
4070
|
+
}
|
|
4071
|
+
}, [account?.address, balanceEndpoint, chains]);
|
|
4072
|
+
useEffect(() => {
|
|
4073
|
+
fetchBalances();
|
|
4074
|
+
}, [fetchBalances]);
|
|
4075
|
+
const handleRefresh = () => {
|
|
4076
|
+
fetchBalances();
|
|
4077
|
+
onRefresh?.();
|
|
4078
|
+
};
|
|
4079
|
+
const filteredTokens = selectedChain ? tokens.filter((t) => t.chainId === selectedChain) : tokens;
|
|
4080
|
+
const isDark = theme === "dark";
|
|
4081
|
+
if (!account) {
|
|
4082
|
+
return /* @__PURE__ */ jsx("div", { className, style: { ...style, textAlign: "center", padding: "24px", color: isDark ? "#9ca3af" : "#6b7280" }, children: "Connect your wallet to view balances" });
|
|
4083
|
+
}
|
|
4084
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { ...containerStyle5, ...style }, children: [
|
|
4085
|
+
showTotalBalance && /* @__PURE__ */ jsx("div", { style: { ...balanceCardStyle, backgroundColor: isDark ? "#1f2937" : "#ffffff", border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}` }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start" }, children: [
|
|
4086
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4087
|
+
/* @__PURE__ */ jsx("p", { style: { margin: "0 0 4px 0", color: isDark ? "#9ca3af" : "#6b7280", fontSize: "14px" }, children: "Total Balance" }),
|
|
4088
|
+
isLoading ? /* @__PURE__ */ jsx("div", { style: { height: "36px", width: "120px", backgroundColor: isDark ? "#374151" : "#e5e7eb", borderRadius: "8px", animation: "pulse 2s infinite" } }) : /* @__PURE__ */ jsx("h2", { style: { margin: 0, color: isDark ? "#ffffff" : "#111827", fontSize: compact ? "24px" : "32px", fontWeight: 700 }, children: formatUSD(totalBalance) }),
|
|
4089
|
+
showPriceChange && !isLoading && /* @__PURE__ */ jsxs("p", { style: { margin: "4px 0 0 0", fontSize: "14px", color: totalChange24h >= 0 ? "#10b981" : "#ef4444" }, children: [
|
|
4090
|
+
totalChange24h >= 0 ? "+" : "",
|
|
4091
|
+
totalChange24h.toFixed(2),
|
|
4092
|
+
"% (24h)"
|
|
4093
|
+
] })
|
|
4094
|
+
] }),
|
|
4095
|
+
/* @__PURE__ */ jsx(
|
|
4096
|
+
"button",
|
|
4097
|
+
{
|
|
4098
|
+
onClick: handleRefresh,
|
|
4099
|
+
disabled: isLoading,
|
|
4100
|
+
style: {
|
|
4101
|
+
padding: "8px 12px",
|
|
4102
|
+
backgroundColor: isDark ? "#374151" : "#e5e7eb",
|
|
4103
|
+
border: "none",
|
|
4104
|
+
borderRadius: "8px",
|
|
4105
|
+
color: isDark ? "#ffffff" : "#111827",
|
|
4106
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
4107
|
+
fontSize: "14px"
|
|
4108
|
+
},
|
|
4109
|
+
children: isLoading ? "..." : "\u21BB"
|
|
4110
|
+
}
|
|
4111
|
+
)
|
|
4112
|
+
] }) }),
|
|
4113
|
+
showChainFilter && chains.length > 1 && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
|
|
4114
|
+
/* @__PURE__ */ jsx(
|
|
4115
|
+
"button",
|
|
4116
|
+
{
|
|
4117
|
+
onClick: () => setSelectedChain(null),
|
|
4118
|
+
style: {
|
|
4119
|
+
padding: "8px 16px",
|
|
4120
|
+
backgroundColor: selectedChain === null ? "#10b981" : isDark ? "#374151" : "#e5e7eb",
|
|
4121
|
+
border: "none",
|
|
4122
|
+
borderRadius: "20px",
|
|
4123
|
+
color: selectedChain === null ? "#ffffff" : isDark ? "#9ca3af" : "#6b7280",
|
|
4124
|
+
cursor: "pointer",
|
|
4125
|
+
fontSize: "14px"
|
|
4126
|
+
},
|
|
4127
|
+
children: "All"
|
|
4128
|
+
}
|
|
4129
|
+
),
|
|
4130
|
+
chains.map((chain) => /* @__PURE__ */ jsxs(
|
|
4131
|
+
"button",
|
|
4132
|
+
{
|
|
4133
|
+
onClick: () => setSelectedChain(chain.id),
|
|
4134
|
+
style: {
|
|
4135
|
+
padding: "8px 16px",
|
|
4136
|
+
backgroundColor: selectedChain === chain.id ? "#10b981" : isDark ? "#374151" : "#e5e7eb",
|
|
4137
|
+
border: "none",
|
|
4138
|
+
borderRadius: "20px",
|
|
4139
|
+
color: selectedChain === chain.id ? "#ffffff" : isDark ? "#9ca3af" : "#6b7280",
|
|
4140
|
+
cursor: "pointer",
|
|
4141
|
+
fontSize: "14px"
|
|
4142
|
+
},
|
|
4143
|
+
children: [
|
|
4144
|
+
CHAIN_INFO[chain.id]?.icon,
|
|
4145
|
+
" ",
|
|
4146
|
+
CHAIN_INFO[chain.id]?.name || `Chain ${chain.id}`
|
|
4147
|
+
]
|
|
4148
|
+
},
|
|
4149
|
+
chain.id
|
|
4150
|
+
))
|
|
4151
|
+
] }),
|
|
4152
|
+
showTokenList && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: isLoading ? Array(3).fill(0).map((_, i) => /* @__PURE__ */ jsx("div", { style: { ...tokenRowStyle, backgroundColor: isDark ? "#374151" : "#f3f4f6", height: "60px", animation: "pulse 2s infinite" } }, i)) : error ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "24px", color: "#ef4444" }, children: error }) : filteredTokens.length === 0 ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "24px", color: isDark ? "#9ca3af" : "#6b7280" }, children: "No tokens found" }) : filteredTokens.map((token, index) => /* @__PURE__ */ jsxs(
|
|
4153
|
+
"div",
|
|
4154
|
+
{
|
|
4155
|
+
style: {
|
|
4156
|
+
...tokenRowStyle,
|
|
4157
|
+
backgroundColor: "transparent"
|
|
4158
|
+
},
|
|
4159
|
+
onClick: () => onTokenClick?.(token),
|
|
4160
|
+
onMouseEnter: (e) => {
|
|
4161
|
+
e.currentTarget.style.backgroundColor = isDark ? "#374151" : "#f3f4f6";
|
|
4162
|
+
},
|
|
4163
|
+
onMouseLeave: (e) => {
|
|
4164
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
4165
|
+
},
|
|
4166
|
+
children: [
|
|
4167
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px" }, children: [
|
|
4168
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
4169
|
+
width: "40px",
|
|
4170
|
+
height: "40px",
|
|
4171
|
+
borderRadius: "50%",
|
|
4172
|
+
backgroundColor: isDark ? "#374151" : "#e5e7eb",
|
|
4173
|
+
display: "flex",
|
|
4174
|
+
alignItems: "center",
|
|
4175
|
+
justifyContent: "center",
|
|
4176
|
+
fontSize: "16px",
|
|
4177
|
+
fontWeight: 600,
|
|
4178
|
+
color: isDark ? "#ffffff" : "#111827"
|
|
4179
|
+
}, children: token.logoURI ? /* @__PURE__ */ jsx("img", { src: token.logoURI, alt: token.symbol, style: { width: "100%", height: "100%", borderRadius: "50%" } }) : token.symbol.slice(0, 2) }),
|
|
4180
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4181
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
4182
|
+
/* @__PURE__ */ jsx("span", { style: { color: isDark ? "#ffffff" : "#111827", fontWeight: 600 }, children: token.symbol }),
|
|
4183
|
+
/* @__PURE__ */ jsx("span", { style: {
|
|
4184
|
+
fontSize: "10px",
|
|
4185
|
+
padding: "2px 6px",
|
|
4186
|
+
backgroundColor: isDark ? "#374151" : "#e5e7eb",
|
|
4187
|
+
borderRadius: "4px",
|
|
4188
|
+
color: isDark ? "#9ca3af" : "#6b7280"
|
|
4189
|
+
}, children: CHAIN_INFO[token.chainId]?.name || token.chain })
|
|
4190
|
+
] }),
|
|
4191
|
+
/* @__PURE__ */ jsxs("span", { style: { color: isDark ? "#9ca3af" : "#6b7280", fontSize: "14px" }, children: [
|
|
4192
|
+
formatBalance(token.balanceFormatted),
|
|
4193
|
+
" ",
|
|
4194
|
+
token.symbol
|
|
4195
|
+
] })
|
|
4196
|
+
] })
|
|
4197
|
+
] }),
|
|
4198
|
+
/* @__PURE__ */ jsxs("div", { style: { textAlign: "right" }, children: [
|
|
4199
|
+
/* @__PURE__ */ jsx("div", { style: { color: isDark ? "#ffffff" : "#111827", fontWeight: 600 }, children: formatUSD(token.balanceUsd) }),
|
|
4200
|
+
showPriceChange && /* @__PURE__ */ jsxs("div", { style: { fontSize: "14px", color: token.priceChange24h >= 0 ? "#10b981" : "#ef4444" }, children: [
|
|
4201
|
+
token.priceChange24h >= 0 ? "+" : "",
|
|
4202
|
+
token.priceChange24h.toFixed(2),
|
|
4203
|
+
"%"
|
|
4204
|
+
] })
|
|
4205
|
+
] })
|
|
4206
|
+
]
|
|
4207
|
+
},
|
|
4208
|
+
`${token.chainId}-${token.symbol}-${index}`
|
|
4209
|
+
)) })
|
|
4210
|
+
] });
|
|
4211
|
+
}
|
|
4212
|
+
function OneBalanceDisplay({
|
|
4213
|
+
theme = "dark",
|
|
4214
|
+
className,
|
|
4215
|
+
style
|
|
4216
|
+
}) {
|
|
4217
|
+
return /* @__PURE__ */ jsx(
|
|
4218
|
+
OneWalletBalance,
|
|
4219
|
+
{
|
|
4220
|
+
theme,
|
|
4221
|
+
className,
|
|
4222
|
+
style,
|
|
4223
|
+
showTotalBalance: true,
|
|
4224
|
+
showTokenList: false,
|
|
4225
|
+
showChainFilter: false,
|
|
4226
|
+
compact: true
|
|
4227
|
+
}
|
|
4228
|
+
);
|
|
4229
|
+
}
|
|
4230
|
+
var galleryStyle = {
|
|
4231
|
+
display: "grid",
|
|
4232
|
+
gap: "16px"
|
|
4233
|
+
};
|
|
4234
|
+
var cardStyle = {
|
|
4235
|
+
backgroundColor: "#1f2937",
|
|
4236
|
+
borderRadius: "16px",
|
|
4237
|
+
overflow: "hidden",
|
|
4238
|
+
border: "1px solid #374151",
|
|
4239
|
+
cursor: "pointer",
|
|
4240
|
+
transition: "transform 0.2s, box-shadow 0.2s"
|
|
4241
|
+
};
|
|
4242
|
+
var imageContainerStyle = {
|
|
4243
|
+
aspectRatio: "1",
|
|
4244
|
+
backgroundColor: "#374151",
|
|
4245
|
+
display: "flex",
|
|
4246
|
+
alignItems: "center",
|
|
4247
|
+
justifyContent: "center",
|
|
4248
|
+
overflow: "hidden"
|
|
4249
|
+
};
|
|
4250
|
+
var infoStyle = {
|
|
4251
|
+
padding: "12px"
|
|
4252
|
+
};
|
|
4253
|
+
function OneNFTGallery({
|
|
4254
|
+
nfts: propNfts,
|
|
4255
|
+
fetchEndpoint = "/api/v1/assets/nft",
|
|
4256
|
+
columns = 3,
|
|
4257
|
+
showCollection = true,
|
|
4258
|
+
showChain = true,
|
|
4259
|
+
theme = "dark",
|
|
4260
|
+
className,
|
|
4261
|
+
style,
|
|
4262
|
+
onNFTClick,
|
|
4263
|
+
onTransfer
|
|
4264
|
+
}) {
|
|
4265
|
+
const client = useThirdwebClient();
|
|
4266
|
+
const account = useActiveAccount();
|
|
4267
|
+
const [nfts, setNfts] = useState(propNfts || []);
|
|
4268
|
+
const [isLoading, setIsLoading] = useState(!propNfts);
|
|
4269
|
+
const [error, setError] = useState(null);
|
|
4270
|
+
const [selectedNFT, setSelectedNFT] = useState(null);
|
|
4271
|
+
const fetchNFTs = useCallback(async () => {
|
|
4272
|
+
if (!account?.address || propNfts) return;
|
|
4273
|
+
setIsLoading(true);
|
|
4274
|
+
setError(null);
|
|
4275
|
+
try {
|
|
4276
|
+
const response = await fetch(`${fetchEndpoint}?address=${account.address}`);
|
|
4277
|
+
const data = await response.json();
|
|
4278
|
+
if (data.success && data.data) {
|
|
4279
|
+
setNfts(data.data.nfts || []);
|
|
4280
|
+
} else {
|
|
4281
|
+
setError(data.error?.message || "Failed to fetch NFTs");
|
|
4282
|
+
}
|
|
4283
|
+
} catch (err) {
|
|
4284
|
+
setError("Failed to load NFTs");
|
|
4285
|
+
} finally {
|
|
4286
|
+
setIsLoading(false);
|
|
4287
|
+
}
|
|
4288
|
+
}, [account?.address, fetchEndpoint, propNfts]);
|
|
4289
|
+
useEffect(() => {
|
|
4290
|
+
fetchNFTs();
|
|
4291
|
+
}, [fetchNFTs]);
|
|
4292
|
+
useEffect(() => {
|
|
4293
|
+
if (propNfts) {
|
|
4294
|
+
setNfts(propNfts);
|
|
4295
|
+
}
|
|
4296
|
+
}, [propNfts]);
|
|
4297
|
+
const isDark = theme === "dark";
|
|
4298
|
+
const gridColumns = {
|
|
4299
|
+
2: "repeat(2, 1fr)",
|
|
4300
|
+
3: "repeat(3, 1fr)",
|
|
4301
|
+
4: "repeat(4, 1fr)"
|
|
4302
|
+
};
|
|
4303
|
+
if (isLoading) {
|
|
4304
|
+
return /* @__PURE__ */ jsx("div", { className, style: { ...style, textAlign: "center", padding: "40px", color: isDark ? "#9ca3af" : "#6b7280" }, children: "Loading NFTs..." });
|
|
4305
|
+
}
|
|
4306
|
+
if (error) {
|
|
4307
|
+
return /* @__PURE__ */ jsx("div", { className, style: { ...style, textAlign: "center", padding: "40px", color: "#ef4444" }, children: error });
|
|
4308
|
+
}
|
|
4309
|
+
if (nfts.length === 0) {
|
|
4310
|
+
return /* @__PURE__ */ jsx("div", { className, style: { ...style, textAlign: "center", padding: "40px", color: isDark ? "#9ca3af" : "#6b7280" }, children: "No NFTs found" });
|
|
4311
|
+
}
|
|
4312
|
+
return /* @__PURE__ */ jsxs("div", { className, style, children: [
|
|
4313
|
+
/* @__PURE__ */ jsx("div", { style: { ...galleryStyle, gridTemplateColumns: gridColumns[columns] }, children: nfts.map((nft) => /* @__PURE__ */ jsxs(
|
|
4314
|
+
"div",
|
|
4315
|
+
{
|
|
4316
|
+
style: {
|
|
4317
|
+
...cardStyle,
|
|
4318
|
+
backgroundColor: isDark ? "#1f2937" : "#ffffff",
|
|
4319
|
+
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`
|
|
4320
|
+
},
|
|
4321
|
+
onClick: () => {
|
|
4322
|
+
setSelectedNFT(nft);
|
|
4323
|
+
onNFTClick?.(nft);
|
|
4324
|
+
},
|
|
4325
|
+
onMouseEnter: (e) => {
|
|
4326
|
+
e.currentTarget.style.transform = "translateY(-4px)";
|
|
4327
|
+
e.currentTarget.style.boxShadow = "0 10px 40px rgba(0,0,0,0.3)";
|
|
4328
|
+
},
|
|
4329
|
+
onMouseLeave: (e) => {
|
|
4330
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
4331
|
+
e.currentTarget.style.boxShadow = "none";
|
|
4332
|
+
},
|
|
4333
|
+
children: [
|
|
4334
|
+
/* @__PURE__ */ jsx("div", { style: { ...imageContainerStyle, backgroundColor: isDark ? "#374151" : "#f3f4f6" }, children: nft.image ? /* @__PURE__ */ jsx(
|
|
4335
|
+
MediaRenderer,
|
|
4336
|
+
{
|
|
4337
|
+
client,
|
|
4338
|
+
src: nft.image,
|
|
4339
|
+
style: { width: "100%", height: "100%", objectFit: "cover" }
|
|
4340
|
+
}
|
|
4341
|
+
) : /* @__PURE__ */ jsx("span", { style: { color: isDark ? "#6b7280" : "#9ca3af", fontSize: "14px" }, children: "No Image" }) }),
|
|
4342
|
+
/* @__PURE__ */ jsxs("div", { style: infoStyle, children: [
|
|
4343
|
+
/* @__PURE__ */ jsx("h4", { style: { margin: "0 0 4px 0", color: isDark ? "#ffffff" : "#111827", fontSize: "14px", fontWeight: 600 }, children: nft.name || `#${nft.tokenId}` }),
|
|
4344
|
+
showCollection && nft.collection && /* @__PURE__ */ jsx("p", { style: { margin: 0, color: isDark ? "#9ca3af" : "#6b7280", fontSize: "12px" }, children: nft.collection.name }),
|
|
4345
|
+
showChain && /* @__PURE__ */ jsx("span", { style: {
|
|
4346
|
+
display: "inline-block",
|
|
4347
|
+
marginTop: "8px",
|
|
4348
|
+
padding: "2px 8px",
|
|
4349
|
+
backgroundColor: isDark ? "#374151" : "#e5e7eb",
|
|
4350
|
+
borderRadius: "4px",
|
|
4351
|
+
fontSize: "10px",
|
|
4352
|
+
color: isDark ? "#9ca3af" : "#6b7280"
|
|
4353
|
+
}, children: nft.chain })
|
|
4354
|
+
] })
|
|
4355
|
+
]
|
|
4356
|
+
},
|
|
4357
|
+
`${nft.contractAddress}-${nft.tokenId}`
|
|
4358
|
+
)) }),
|
|
4359
|
+
selectedNFT && /* @__PURE__ */ jsx(
|
|
4360
|
+
"div",
|
|
4361
|
+
{
|
|
4362
|
+
style: {
|
|
4363
|
+
position: "fixed",
|
|
4364
|
+
inset: 0,
|
|
4365
|
+
backgroundColor: "rgba(0,0,0,0.8)",
|
|
4366
|
+
display: "flex",
|
|
4367
|
+
alignItems: "center",
|
|
4368
|
+
justifyContent: "center",
|
|
4369
|
+
zIndex: 1e3
|
|
4370
|
+
},
|
|
4371
|
+
onClick: () => setSelectedNFT(null),
|
|
4372
|
+
children: /* @__PURE__ */ jsxs(
|
|
4373
|
+
"div",
|
|
4374
|
+
{
|
|
4375
|
+
style: {
|
|
4376
|
+
backgroundColor: isDark ? "#1f2937" : "#ffffff",
|
|
4377
|
+
borderRadius: "16px",
|
|
4378
|
+
padding: "24px",
|
|
4379
|
+
maxWidth: "500px",
|
|
4380
|
+
width: "90%",
|
|
4381
|
+
maxHeight: "90vh",
|
|
4382
|
+
overflow: "auto"
|
|
4383
|
+
},
|
|
4384
|
+
onClick: (e) => e.stopPropagation(),
|
|
4385
|
+
children: [
|
|
4386
|
+
selectedNFT.image && /* @__PURE__ */ jsx(
|
|
4387
|
+
MediaRenderer,
|
|
4388
|
+
{
|
|
4389
|
+
client,
|
|
4390
|
+
src: selectedNFT.image,
|
|
4391
|
+
style: { width: "100%", borderRadius: "12px", marginBottom: "16px" }
|
|
4392
|
+
}
|
|
4393
|
+
),
|
|
4394
|
+
/* @__PURE__ */ jsx("h3", { style: { margin: "0 0 8px 0", color: isDark ? "#ffffff" : "#111827" }, children: selectedNFT.name || `#${selectedNFT.tokenId}` }),
|
|
4395
|
+
selectedNFT.description && /* @__PURE__ */ jsx("p", { style: { margin: "0 0 16px 0", color: isDark ? "#9ca3af" : "#6b7280", fontSize: "14px" }, children: selectedNFT.description }),
|
|
4396
|
+
selectedNFT.attributes && selectedNFT.attributes.length > 0 && /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px", marginBottom: "16px" }, children: selectedNFT.attributes.map((attr, i) => /* @__PURE__ */ jsxs(
|
|
4397
|
+
"div",
|
|
4398
|
+
{
|
|
4399
|
+
style: {
|
|
4400
|
+
padding: "8px 12px",
|
|
4401
|
+
backgroundColor: isDark ? "#374151" : "#f3f4f6",
|
|
4402
|
+
borderRadius: "8px"
|
|
4403
|
+
},
|
|
4404
|
+
children: [
|
|
4405
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: "10px", color: isDark ? "#9ca3af" : "#6b7280" }, children: attr.trait_type }),
|
|
4406
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: "14px", color: isDark ? "#ffffff" : "#111827", fontWeight: 500 }, children: attr.value })
|
|
4407
|
+
]
|
|
4408
|
+
},
|
|
4409
|
+
i
|
|
4410
|
+
)) }),
|
|
4411
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px" }, children: [
|
|
4412
|
+
/* @__PURE__ */ jsx(
|
|
4413
|
+
"button",
|
|
4414
|
+
{
|
|
4415
|
+
onClick: () => setSelectedNFT(null),
|
|
4416
|
+
style: {
|
|
4417
|
+
flex: 1,
|
|
4418
|
+
padding: "12px",
|
|
4419
|
+
backgroundColor: "transparent",
|
|
4420
|
+
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
|
|
4421
|
+
borderRadius: "8px",
|
|
4422
|
+
color: isDark ? "#9ca3af" : "#6b7280",
|
|
4423
|
+
cursor: "pointer"
|
|
4424
|
+
},
|
|
4425
|
+
children: "Close"
|
|
4426
|
+
}
|
|
4427
|
+
),
|
|
4428
|
+
onTransfer && /* @__PURE__ */ jsx(
|
|
4429
|
+
"button",
|
|
4430
|
+
{
|
|
4431
|
+
onClick: () => {
|
|
4432
|
+
onTransfer(selectedNFT);
|
|
4433
|
+
setSelectedNFT(null);
|
|
4434
|
+
},
|
|
4435
|
+
style: {
|
|
4436
|
+
flex: 1,
|
|
4437
|
+
padding: "12px",
|
|
4438
|
+
backgroundColor: "#10b981",
|
|
4439
|
+
border: "none",
|
|
4440
|
+
borderRadius: "8px",
|
|
4441
|
+
color: "#ffffff",
|
|
4442
|
+
fontWeight: 600,
|
|
4443
|
+
cursor: "pointer"
|
|
4444
|
+
},
|
|
4445
|
+
children: "Transfer"
|
|
4446
|
+
}
|
|
4447
|
+
)
|
|
4448
|
+
] })
|
|
4449
|
+
]
|
|
4450
|
+
}
|
|
4451
|
+
)
|
|
4452
|
+
}
|
|
4453
|
+
)
|
|
4454
|
+
] });
|
|
4455
|
+
}
|
|
4456
|
+
function generateQRMatrix(data) {
|
|
4457
|
+
const size = 21;
|
|
4458
|
+
const matrix = Array(size).fill(null).map(() => Array(size).fill(false));
|
|
4459
|
+
const addFinderPattern = (x, y) => {
|
|
4460
|
+
for (let i = 0; i < 7; i++) {
|
|
4461
|
+
for (let j = 0; j < 7; j++) {
|
|
4462
|
+
if (i === 0 || i === 6 || j === 0 || j === 6 || i >= 2 && i <= 4 && j >= 2 && j <= 4) {
|
|
4463
|
+
matrix[y + i][x + j] = true;
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
};
|
|
4468
|
+
addFinderPattern(0, 0);
|
|
4469
|
+
addFinderPattern(14, 0);
|
|
4470
|
+
addFinderPattern(0, 14);
|
|
4471
|
+
let hash = 0;
|
|
4472
|
+
for (let i = 0; i < data.length; i++) {
|
|
4473
|
+
hash = (hash << 5) - hash + data.charCodeAt(i);
|
|
4474
|
+
hash = hash & hash;
|
|
4475
|
+
}
|
|
4476
|
+
for (let i = 8; i < 13; i++) {
|
|
4477
|
+
for (let j = 8; j < 13; j++) {
|
|
4478
|
+
matrix[i][j] = (hash >> (i * 21 + j) % 32 & 1) === 1;
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
return matrix;
|
|
4482
|
+
}
|
|
4483
|
+
function QRCode({ data, size = 200, isDark = true }) {
|
|
4484
|
+
const matrix = generateQRMatrix(data);
|
|
4485
|
+
const cellSize = size / matrix.length;
|
|
4486
|
+
return /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [
|
|
4487
|
+
/* @__PURE__ */ jsx("rect", { width: size, height: size, fill: isDark ? "#ffffff" : "#ffffff", rx: "8" }),
|
|
4488
|
+
matrix.map(
|
|
4489
|
+
(row, y) => row.map(
|
|
4490
|
+
(cell, x) => cell ? /* @__PURE__ */ jsx(
|
|
4491
|
+
"rect",
|
|
4492
|
+
{
|
|
4493
|
+
x: x * cellSize,
|
|
4494
|
+
y: y * cellSize,
|
|
4495
|
+
width: cellSize,
|
|
4496
|
+
height: cellSize,
|
|
4497
|
+
fill: isDark ? "#111827" : "#111827"
|
|
4498
|
+
},
|
|
4499
|
+
`${x}-${y}`
|
|
4500
|
+
) : null
|
|
4501
|
+
)
|
|
4502
|
+
)
|
|
4503
|
+
] });
|
|
4504
|
+
}
|
|
4505
|
+
var containerStyle6 = {
|
|
4506
|
+
display: "flex",
|
|
4507
|
+
flexDirection: "column",
|
|
4508
|
+
alignItems: "center",
|
|
4509
|
+
gap: "20px",
|
|
4510
|
+
padding: "24px",
|
|
4511
|
+
backgroundColor: "#1f2937",
|
|
4512
|
+
borderRadius: "16px",
|
|
4513
|
+
border: "1px solid #374151"
|
|
4514
|
+
};
|
|
4515
|
+
var addressStyle = {
|
|
4516
|
+
display: "flex",
|
|
4517
|
+
alignItems: "center",
|
|
4518
|
+
gap: "8px",
|
|
4519
|
+
padding: "12px 16px",
|
|
4520
|
+
backgroundColor: "#374151",
|
|
4521
|
+
borderRadius: "12px",
|
|
4522
|
+
maxWidth: "100%"
|
|
4523
|
+
};
|
|
4524
|
+
var buttonStyle5 = {
|
|
4525
|
+
padding: "8px 16px",
|
|
4526
|
+
backgroundColor: "#10b981",
|
|
4527
|
+
color: "#ffffff",
|
|
4528
|
+
border: "none",
|
|
4529
|
+
borderRadius: "8px",
|
|
4530
|
+
cursor: "pointer",
|
|
4531
|
+
fontSize: "14px",
|
|
4532
|
+
fontWeight: 500
|
|
4533
|
+
};
|
|
4534
|
+
var CHAIN_INFO2 = {
|
|
4535
|
+
1: { name: "Ethereum", icon: "\u27E0" },
|
|
4536
|
+
8453: { name: "Base", icon: "\u{1F535}" },
|
|
4537
|
+
137: { name: "Polygon", icon: "\u{1F7E3}" },
|
|
4538
|
+
42161: { name: "Arbitrum", icon: "\u{1F537}" },
|
|
4539
|
+
10: { name: "Optimism", icon: "\u{1F534}" }
|
|
4540
|
+
};
|
|
4541
|
+
function OneReceiveWidget({
|
|
4542
|
+
chains = [base, ethereum, polygon, arbitrum],
|
|
4543
|
+
defaultChain = base,
|
|
4544
|
+
showChainSelector = true,
|
|
4545
|
+
showCopyButton = true,
|
|
4546
|
+
showQRCode = true,
|
|
4547
|
+
theme = "dark",
|
|
4548
|
+
className,
|
|
4549
|
+
style,
|
|
4550
|
+
qrSize = 200,
|
|
4551
|
+
onCopy,
|
|
4552
|
+
onChainChange
|
|
4553
|
+
}) {
|
|
4554
|
+
const account = useActiveAccount();
|
|
4555
|
+
const [selectedChain, setSelectedChain] = useState(defaultChain);
|
|
4556
|
+
const [copied, setCopied] = useState(false);
|
|
4557
|
+
const address = account?.address || "";
|
|
4558
|
+
const isDark = theme === "dark";
|
|
4559
|
+
const handleCopy = async () => {
|
|
4560
|
+
if (!address) return;
|
|
4561
|
+
try {
|
|
4562
|
+
await navigator.clipboard.writeText(address);
|
|
4563
|
+
setCopied(true);
|
|
4564
|
+
onCopy?.(address);
|
|
4565
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
4566
|
+
} catch (err) {
|
|
4567
|
+
console.error("Failed to copy:", err);
|
|
4568
|
+
}
|
|
4569
|
+
};
|
|
4570
|
+
const handleChainChange = (chain) => {
|
|
4571
|
+
setSelectedChain(chain);
|
|
4572
|
+
onChainChange?.(chain);
|
|
4573
|
+
};
|
|
4574
|
+
if (!account) {
|
|
4575
|
+
return /* @__PURE__ */ jsx("div", { className, style: { ...style, textAlign: "center", padding: "24px", color: isDark ? "#9ca3af" : "#6b7280" }, children: "Connect your wallet to receive funds" });
|
|
4576
|
+
}
|
|
4577
|
+
return /* @__PURE__ */ jsxs(
|
|
4578
|
+
"div",
|
|
4579
|
+
{
|
|
4580
|
+
className,
|
|
4581
|
+
style: {
|
|
4582
|
+
...containerStyle6,
|
|
4583
|
+
backgroundColor: isDark ? "#1f2937" : "#ffffff",
|
|
4584
|
+
border: `1px solid ${isDark ? "#374151" : "#e5e7eb"}`,
|
|
4585
|
+
...style
|
|
4586
|
+
},
|
|
4587
|
+
children: [
|
|
4588
|
+
/* @__PURE__ */ jsx("h3", { style: { margin: 0, color: isDark ? "#ffffff" : "#111827", fontSize: "18px", fontWeight: 600 }, children: "Receive" }),
|
|
4589
|
+
showChainSelector && chains.length > 1 && /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap", justifyContent: "center" }, children: chains.map((chain) => /* @__PURE__ */ jsxs(
|
|
4590
|
+
"button",
|
|
4591
|
+
{
|
|
4592
|
+
onClick: () => handleChainChange(chain),
|
|
4593
|
+
style: {
|
|
4594
|
+
padding: "8px 12px",
|
|
4595
|
+
backgroundColor: selectedChain.id === chain.id ? "#10b981" : isDark ? "#374151" : "#e5e7eb",
|
|
4596
|
+
border: "none",
|
|
4597
|
+
borderRadius: "8px",
|
|
4598
|
+
color: selectedChain.id === chain.id ? "#ffffff" : isDark ? "#9ca3af" : "#6b7280",
|
|
4599
|
+
cursor: "pointer",
|
|
4600
|
+
fontSize: "12px"
|
|
4601
|
+
},
|
|
4602
|
+
children: [
|
|
4603
|
+
CHAIN_INFO2[chain.id]?.icon,
|
|
4604
|
+
" ",
|
|
4605
|
+
CHAIN_INFO2[chain.id]?.name
|
|
4606
|
+
]
|
|
4607
|
+
},
|
|
4608
|
+
chain.id
|
|
4609
|
+
)) }),
|
|
4610
|
+
showQRCode && /* @__PURE__ */ jsx("div", { style: { padding: "16px", backgroundColor: "#ffffff", borderRadius: "12px" }, children: /* @__PURE__ */ jsx(QRCode, { data: address, size: qrSize, isDark }) }),
|
|
4611
|
+
/* @__PURE__ */ jsx("div", { style: { ...addressStyle, backgroundColor: isDark ? "#374151" : "#f3f4f6", width: "100%" }, children: /* @__PURE__ */ jsx("span", { style: {
|
|
4612
|
+
color: isDark ? "#ffffff" : "#111827",
|
|
4613
|
+
fontSize: "14px",
|
|
4614
|
+
fontFamily: "monospace",
|
|
4615
|
+
flex: 1,
|
|
4616
|
+
overflow: "hidden",
|
|
4617
|
+
textOverflow: "ellipsis"
|
|
4618
|
+
}, children: address }) }),
|
|
4619
|
+
showCopyButton && /* @__PURE__ */ jsx(
|
|
4620
|
+
"button",
|
|
4621
|
+
{
|
|
4622
|
+
onClick: handleCopy,
|
|
4623
|
+
style: {
|
|
4624
|
+
...buttonStyle5,
|
|
4625
|
+
backgroundColor: copied ? "#059669" : "#10b981",
|
|
4626
|
+
width: "100%"
|
|
4627
|
+
},
|
|
4628
|
+
children: copied ? "\u2713 Copied!" : "Copy Address"
|
|
4629
|
+
}
|
|
4630
|
+
),
|
|
4631
|
+
/* @__PURE__ */ jsxs("p", { style: {
|
|
4632
|
+
margin: 0,
|
|
4633
|
+
color: isDark ? "#9ca3af" : "#6b7280",
|
|
4634
|
+
fontSize: "12px",
|
|
4635
|
+
textAlign: "center"
|
|
4636
|
+
}, children: [
|
|
4637
|
+
"Only send ",
|
|
4638
|
+
CHAIN_INFO2[selectedChain.id]?.name || "compatible",
|
|
4639
|
+
" assets to this address"
|
|
4640
|
+
] })
|
|
4641
|
+
]
|
|
4642
|
+
}
|
|
4643
|
+
);
|
|
4644
|
+
}
|
|
4645
|
+
function useWalletBalance2(walletAddress, options = {}) {
|
|
4646
|
+
const {
|
|
4647
|
+
chains,
|
|
4648
|
+
autoRefresh = false,
|
|
4649
|
+
refreshInterval = 6e4,
|
|
4650
|
+
// 1 minute
|
|
4651
|
+
engineUrl,
|
|
4652
|
+
clientId
|
|
4653
|
+
} = options;
|
|
4654
|
+
const [balance, setBalance] = useState(null);
|
|
4655
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
4656
|
+
const [error, setError] = useState(null);
|
|
4657
|
+
const engineRef = useRef(createOneEngineClient({
|
|
4658
|
+
baseUrl: engineUrl,
|
|
4659
|
+
clientId
|
|
4660
|
+
}));
|
|
4661
|
+
const fetchBalance = useCallback(async () => {
|
|
4662
|
+
if (!walletAddress) {
|
|
4663
|
+
setBalance(null);
|
|
4664
|
+
return;
|
|
4665
|
+
}
|
|
4666
|
+
setIsLoading(true);
|
|
4667
|
+
setError(null);
|
|
4668
|
+
try {
|
|
4669
|
+
const result = await engineRef.current.getWalletBalance(walletAddress, chains);
|
|
4670
|
+
if (result.success && result.data) {
|
|
4671
|
+
setBalance(result.data);
|
|
4672
|
+
} else {
|
|
4673
|
+
setError(result.error?.message || "Failed to fetch balance");
|
|
4674
|
+
}
|
|
4675
|
+
} catch (err) {
|
|
4676
|
+
setError(err instanceof Error ? err.message : "Failed to fetch balance");
|
|
4677
|
+
} finally {
|
|
4678
|
+
setIsLoading(false);
|
|
4679
|
+
}
|
|
4680
|
+
}, [walletAddress, chains]);
|
|
4681
|
+
useEffect(() => {
|
|
4682
|
+
fetchBalance();
|
|
4683
|
+
}, [fetchBalance]);
|
|
4684
|
+
useEffect(() => {
|
|
4685
|
+
if (!autoRefresh || !walletAddress) return;
|
|
4686
|
+
const interval = setInterval(fetchBalance, refreshInterval);
|
|
4687
|
+
return () => clearInterval(interval);
|
|
4688
|
+
}, [autoRefresh, refreshInterval, fetchBalance, walletAddress]);
|
|
4689
|
+
return {
|
|
4690
|
+
balance,
|
|
4691
|
+
tokens: balance?.tokens || [],
|
|
4692
|
+
totalUsd: balance?.totalUsd || 0,
|
|
4693
|
+
change24h: balance?.change24h || 0,
|
|
4694
|
+
changePercent24h: balance?.changePercent24h || 0,
|
|
4695
|
+
isLoading,
|
|
4696
|
+
error,
|
|
4697
|
+
refetch: fetchBalance
|
|
4698
|
+
};
|
|
4699
|
+
}
|
|
4700
|
+
function useTokenPrice(symbol, options = {}) {
|
|
4701
|
+
const { autoRefresh = false, refreshInterval = 3e4, engineUrl, clientId } = options;
|
|
4702
|
+
const [price, setPrice] = useState(null);
|
|
4703
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
4704
|
+
const [error, setError] = useState(null);
|
|
4705
|
+
const engineRef = useRef(createOneEngineClient({
|
|
4706
|
+
baseUrl: engineUrl,
|
|
4707
|
+
clientId
|
|
4708
|
+
}));
|
|
4709
|
+
const fetchPrice = useCallback(async () => {
|
|
4710
|
+
if (!symbol) return;
|
|
4711
|
+
setIsLoading(true);
|
|
4712
|
+
setError(null);
|
|
4713
|
+
try {
|
|
4714
|
+
const result = await engineRef.current.getTokenPrices([symbol]);
|
|
4715
|
+
if (result.success && result.data && result.data[symbol]) {
|
|
4716
|
+
const priceData = result.data[symbol];
|
|
4717
|
+
setPrice({
|
|
4718
|
+
symbol,
|
|
4719
|
+
price: priceData.price,
|
|
4720
|
+
change24h: priceData.change24h,
|
|
4721
|
+
changePercent24h: priceData.change24h,
|
|
4722
|
+
// Same as change24h for percentage
|
|
4723
|
+
marketCap: priceData.marketCap,
|
|
4724
|
+
volume24h: 0,
|
|
4725
|
+
// Not provided by engine
|
|
4726
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4727
|
+
});
|
|
4728
|
+
} else {
|
|
4729
|
+
setError(result.error?.message || "Failed to fetch price");
|
|
4730
|
+
}
|
|
4731
|
+
} catch (err) {
|
|
4732
|
+
setError(err instanceof Error ? err.message : "Failed to fetch price");
|
|
4733
|
+
} finally {
|
|
4734
|
+
setIsLoading(false);
|
|
4735
|
+
}
|
|
4736
|
+
}, [symbol]);
|
|
4737
|
+
useEffect(() => {
|
|
4738
|
+
fetchPrice();
|
|
4739
|
+
}, [fetchPrice]);
|
|
4740
|
+
useEffect(() => {
|
|
4741
|
+
if (!autoRefresh) return;
|
|
4742
|
+
const interval = setInterval(fetchPrice, refreshInterval);
|
|
4743
|
+
return () => clearInterval(interval);
|
|
4744
|
+
}, [autoRefresh, refreshInterval, fetchPrice]);
|
|
4745
|
+
return {
|
|
4746
|
+
price,
|
|
4747
|
+
isLoading,
|
|
4748
|
+
error,
|
|
4749
|
+
refetch: fetchPrice
|
|
4750
|
+
};
|
|
4751
|
+
}
|
|
4752
|
+
function useTokenPrices(symbols, options = {}) {
|
|
4753
|
+
const { autoRefresh = false, refreshInterval = 3e4, engineUrl, clientId } = options;
|
|
4754
|
+
const [prices, setPrices] = useState({});
|
|
4755
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
4756
|
+
const [error, setError] = useState(null);
|
|
4757
|
+
const engineRef = useRef(createOneEngineClient({
|
|
4758
|
+
baseUrl: engineUrl,
|
|
4759
|
+
clientId
|
|
4760
|
+
}));
|
|
4761
|
+
const fetchPrices = useCallback(async () => {
|
|
4762
|
+
if (symbols.length === 0) return;
|
|
4763
|
+
setIsLoading(true);
|
|
4764
|
+
setError(null);
|
|
4765
|
+
try {
|
|
4766
|
+
const result = await engineRef.current.getTokenPrices(symbols);
|
|
4767
|
+
if (result.success && result.data) {
|
|
4768
|
+
const priceMap = {};
|
|
4769
|
+
for (const sym of symbols) {
|
|
4770
|
+
if (result.data[sym]) {
|
|
4771
|
+
priceMap[sym] = {
|
|
4772
|
+
symbol: sym,
|
|
4773
|
+
price: result.data[sym].price,
|
|
4774
|
+
change24h: result.data[sym].change24h,
|
|
4775
|
+
changePercent24h: result.data[sym].change24h,
|
|
4776
|
+
marketCap: result.data[sym].marketCap,
|
|
4777
|
+
volume24h: 0,
|
|
4778
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4779
|
+
};
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4782
|
+
setPrices(priceMap);
|
|
4783
|
+
} else {
|
|
4784
|
+
setError(result.error?.message || "Failed to fetch prices");
|
|
4785
|
+
}
|
|
4786
|
+
} catch (err) {
|
|
4787
|
+
setError(err instanceof Error ? err.message : "Failed to fetch prices");
|
|
4788
|
+
} finally {
|
|
4789
|
+
setIsLoading(false);
|
|
4790
|
+
}
|
|
4791
|
+
}, [symbols]);
|
|
4792
|
+
useEffect(() => {
|
|
4793
|
+
fetchPrices();
|
|
4794
|
+
}, [fetchPrices]);
|
|
4795
|
+
useEffect(() => {
|
|
4796
|
+
if (!autoRefresh) return;
|
|
4797
|
+
const interval = setInterval(fetchPrices, refreshInterval);
|
|
4798
|
+
return () => clearInterval(interval);
|
|
4799
|
+
}, [autoRefresh, refreshInterval, fetchPrices]);
|
|
4800
|
+
return {
|
|
4801
|
+
prices,
|
|
4802
|
+
isLoading,
|
|
4803
|
+
error,
|
|
4804
|
+
refetch: fetchPrices
|
|
4805
|
+
};
|
|
4806
|
+
}
|
|
4807
|
+
|
|
4808
|
+
// src/utils/index.ts
|
|
4809
|
+
function shortenAddress(address, chars = 4) {
|
|
4810
|
+
if (!address) return "";
|
|
4811
|
+
return `${address.slice(0, chars + 2)}...${address.slice(-chars)}`;
|
|
4812
|
+
}
|
|
4813
|
+
function isValidAddress(address) {
|
|
4814
|
+
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
4815
|
+
}
|
|
4816
|
+
function checksumAddress(address) {
|
|
4817
|
+
return address.toLowerCase();
|
|
4818
|
+
}
|
|
4819
|
+
function formatNumber(value, options = {}) {
|
|
4820
|
+
const { decimals = 2, compact = false, currency, locale = "en-US" } = options;
|
|
4821
|
+
if (currency) {
|
|
4822
|
+
return new Intl.NumberFormat(locale, {
|
|
4823
|
+
style: "currency",
|
|
4824
|
+
currency,
|
|
4825
|
+
minimumFractionDigits: decimals,
|
|
4826
|
+
maximumFractionDigits: decimals,
|
|
4827
|
+
notation: compact ? "compact" : "standard"
|
|
4828
|
+
}).format(value);
|
|
4829
|
+
}
|
|
4830
|
+
return new Intl.NumberFormat(locale, {
|
|
4831
|
+
minimumFractionDigits: decimals,
|
|
4832
|
+
maximumFractionDigits: decimals,
|
|
4833
|
+
notation: compact ? "compact" : "standard"
|
|
4834
|
+
}).format(value);
|
|
4835
|
+
}
|
|
4836
|
+
function formatUSD2(value, compact = false) {
|
|
4837
|
+
return formatNumber(value, { currency: "USD", compact });
|
|
4838
|
+
}
|
|
4839
|
+
function formatPercent(value, decimals = 2) {
|
|
4840
|
+
const sign = value >= 0 ? "+" : "";
|
|
4841
|
+
return `${sign}${value.toFixed(decimals)}%`;
|
|
4842
|
+
}
|
|
4843
|
+
function formatTokenAmount(amount, decimals = 6) {
|
|
4844
|
+
if (amount === 0) return "0";
|
|
4845
|
+
if (amount < 1e-6) return "<0.000001";
|
|
4846
|
+
if (amount < 1) return amount.toFixed(decimals);
|
|
4847
|
+
if (amount < 1e3) return amount.toFixed(4);
|
|
4848
|
+
if (amount < 1e6) return formatNumber(amount, { decimals: 2 });
|
|
4849
|
+
return formatNumber(amount, { decimals: 2, compact: true });
|
|
4850
|
+
}
|
|
4851
|
+
function formatDate(date, options = {
|
|
4852
|
+
year: "numeric",
|
|
4853
|
+
month: "short",
|
|
4854
|
+
day: "numeric"
|
|
4855
|
+
}) {
|
|
4856
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
4857
|
+
return d.toLocaleDateString("en-US", options);
|
|
4858
|
+
}
|
|
4859
|
+
function formatDateTime(date) {
|
|
4860
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
4861
|
+
return d.toLocaleString("en-US", {
|
|
4862
|
+
year: "numeric",
|
|
4863
|
+
month: "short",
|
|
4864
|
+
day: "numeric",
|
|
4865
|
+
hour: "2-digit",
|
|
4866
|
+
minute: "2-digit"
|
|
4867
|
+
});
|
|
4868
|
+
}
|
|
4869
|
+
function formatRelativeTime(date) {
|
|
4870
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
4871
|
+
const now = /* @__PURE__ */ new Date();
|
|
4872
|
+
const diffMs = now.getTime() - d.getTime();
|
|
4873
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
4874
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
4875
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
4876
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
4877
|
+
if (diffSec < 60) return "just now";
|
|
4878
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
4879
|
+
if (diffHour < 24) return `${diffHour}h ago`;
|
|
4880
|
+
if (diffDay < 7) return `${diffDay}d ago`;
|
|
4881
|
+
return formatDate(d);
|
|
4882
|
+
}
|
|
4883
|
+
function isValidEmail(email) {
|
|
4884
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4885
|
+
return emailRegex.test(email);
|
|
4886
|
+
}
|
|
4887
|
+
function isValidPhone(phone) {
|
|
4888
|
+
const phoneRegex = /^\+?[1-9]\d{1,14}$/;
|
|
4889
|
+
return phoneRegex.test(phone.replace(/[\s-()]/g, ""));
|
|
4890
|
+
}
|
|
4891
|
+
function capitalize(str) {
|
|
4892
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
4893
|
+
}
|
|
4894
|
+
function truncate(str, length) {
|
|
4895
|
+
if (str.length <= length) return str;
|
|
4896
|
+
return `${str.slice(0, length)}...`;
|
|
4897
|
+
}
|
|
4898
|
+
function slugify(str) {
|
|
4899
|
+
return str.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
4900
|
+
}
|
|
4901
|
+
function sleep(ms) {
|
|
4902
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4903
|
+
}
|
|
4904
|
+
async function retry(fn, options = {}) {
|
|
4905
|
+
const { maxAttempts = 3, delay = 1e3, backoff = 2 } = options;
|
|
4906
|
+
let lastError;
|
|
4907
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
4908
|
+
try {
|
|
4909
|
+
return await fn();
|
|
4910
|
+
} catch (error) {
|
|
4911
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
4912
|
+
if (attempt < maxAttempts) {
|
|
4913
|
+
await sleep(delay * Math.pow(backoff, attempt - 1));
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4917
|
+
throw lastError;
|
|
4918
|
+
}
|
|
4919
|
+
function omit(obj, keys) {
|
|
4920
|
+
const result = { ...obj };
|
|
4921
|
+
for (const key of keys) {
|
|
4922
|
+
delete result[key];
|
|
4923
|
+
}
|
|
4924
|
+
return result;
|
|
4925
|
+
}
|
|
4926
|
+
function pick(obj, keys) {
|
|
4927
|
+
const result = {};
|
|
4928
|
+
for (const key of keys) {
|
|
4929
|
+
if (key in obj) {
|
|
4930
|
+
result[key] = obj[key];
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
return result;
|
|
4934
|
+
}
|
|
4935
|
+
var OneSDKError = class extends Error {
|
|
4936
|
+
constructor(message, code, details) {
|
|
4937
|
+
super(message);
|
|
4938
|
+
this.name = "OneSDKError";
|
|
4939
|
+
this.code = code;
|
|
4940
|
+
this.details = details;
|
|
4941
|
+
}
|
|
4942
|
+
};
|
|
4943
|
+
function isOneSDKError(error) {
|
|
4944
|
+
return error instanceof OneSDKError;
|
|
4945
|
+
}
|
|
4946
|
+
|
|
4947
|
+
export { CHAIN_CONFIGS, CHAIN_IDS, COINGECKO_IDS, DEFAULT_CHAIN_ID, OneApproveButton, OneBalanceDisplay, OneBuyBTCWidget, OneBuyETHWidget, OneBuyUSDCWidget, OneBuyUSDTWidget, OneConnectButton, OneConnectButtonFull, OneConnectButtonSimple, OneContext, OneCrossChainSwap, OneCryptoOnlyPayWidget, OneDirectPayWidget, OneEngineClient, OneFiatOnlyPayWidget, OneFundWalletWidget, OneNFTGallery, OneOfframpWidget, OneOnrampWidget, OnePayWidget, OneProvider, OneReceiveWidget, OneSDKError, OneSameChainSwap, OneSellETHWidget, OneSellUSDCWidget, OneSellUSDTWidget, OneSendETHButton, OneSendETHWidget, OneSendUSDCWidget, OneSendWidget, OneSwapWidget, OneThirdwebProvider, OneTransactionButton, OneWalletBalance, PriceService, SUPPORTED_CHAINS, SupabaseService, TOKEN_NAMES, capitalize, checksumAddress, createOneEngineClient, createSupabaseClient, fetchChains, formatDate, formatDateTime, formatNumber, formatPercent, formatRelativeTime, formatTokenAmount, formatUSD2 as formatUSD, getChainById, getChainByName, getChainConfig, getChains, getConfig, getEngineUrl, getRecommendedChains, getSmartWalletChains, initOneSDK, isInitialized, isOneSDKError, isValidAddress, isValidEmail, isValidPhone, omit, pick, priceService, retry, shortenAddress, sleep, slugify, truncate, useOne, useOneAuth, useOneEngine, useOneOnramp, useOneSwap, useOneTrading, useOneWallet, useThirdwebClient, useTokenPrice, useTokenPrices, useWalletBalance2 as useWalletBalance };
|
|
4948
|
+
//# sourceMappingURL=index.mjs.map
|
|
4949
|
+
//# sourceMappingURL=index.mjs.map
|