stellar-wallet-kit 2.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/LICENSE +21 -0
- package/README.md +588 -0
- package/dist/index.d.mts +172 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +840 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +821 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +63 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,840 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React3 = require('react');
|
|
4
|
+
var freighterApi = require('@stellar/freighter-api');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
9
|
+
|
|
10
|
+
// src/context/WalletContext.tsx
|
|
11
|
+
|
|
12
|
+
// src/types/index.ts
|
|
13
|
+
var WalletType = /* @__PURE__ */ ((WalletType2) => {
|
|
14
|
+
WalletType2["FREIGHTER"] = "freighter";
|
|
15
|
+
return WalletType2;
|
|
16
|
+
})(WalletType || {});
|
|
17
|
+
var NetworkType = /* @__PURE__ */ ((NetworkType2) => {
|
|
18
|
+
NetworkType2["PUBLIC"] = "PUBLIC";
|
|
19
|
+
NetworkType2["TESTNET"] = "TESTNET";
|
|
20
|
+
NetworkType2["FUTURENET"] = "FUTURENET";
|
|
21
|
+
NetworkType2["STANDALONE"] = "STANDALONE";
|
|
22
|
+
return NetworkType2;
|
|
23
|
+
})(NetworkType || {});
|
|
24
|
+
var FreighterAdapter = class {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.type = "freighter" /* FREIGHTER */;
|
|
27
|
+
}
|
|
28
|
+
async isAvailable() {
|
|
29
|
+
try {
|
|
30
|
+
return await freighterApi.isConnected();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error("Error checking Freighter availability:", error);
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async connect() {
|
|
37
|
+
try {
|
|
38
|
+
const connected = await freighterApi.isConnected();
|
|
39
|
+
if (!connected) {
|
|
40
|
+
throw new Error("Freighter wallet is not installed");
|
|
41
|
+
}
|
|
42
|
+
const allowed = await freighterApi.isAllowed();
|
|
43
|
+
if (!allowed) {
|
|
44
|
+
await freighterApi.setAllowed();
|
|
45
|
+
}
|
|
46
|
+
const userInfo = await freighterApi.getUserInfo();
|
|
47
|
+
if (!userInfo || !userInfo.publicKey) {
|
|
48
|
+
throw new Error("Failed to get user information from Freighter");
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
address: userInfo.publicKey,
|
|
52
|
+
publicKey: userInfo.publicKey
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error("Error connecting to Freighter:", error);
|
|
56
|
+
throw new Error(`Failed to connect to Freighter: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async disconnect() {
|
|
60
|
+
console.log("Freighter disconnect requested - user must disconnect from extension");
|
|
61
|
+
}
|
|
62
|
+
async getPublicKey() {
|
|
63
|
+
try {
|
|
64
|
+
const allowed = await freighterApi.isAllowed();
|
|
65
|
+
if (!allowed) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const userInfo = await freighterApi.getUserInfo();
|
|
69
|
+
return userInfo?.publicKey || null;
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error("Error getting public key:", error);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async getNetwork() {
|
|
76
|
+
try {
|
|
77
|
+
const network = await freighterApi.getNetwork();
|
|
78
|
+
return network;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error("Error getting network:", error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async signTransaction(xdr, options) {
|
|
85
|
+
try {
|
|
86
|
+
const result = await freighterApi.signTransaction(xdr, {
|
|
87
|
+
network: options?.network,
|
|
88
|
+
networkPassphrase: options?.networkPassphrase,
|
|
89
|
+
accountToSign: options?.accountToSign
|
|
90
|
+
});
|
|
91
|
+
if (!result || typeof result !== "string") {
|
|
92
|
+
throw new Error("Invalid response from Freighter");
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
signedTxXdr: result
|
|
96
|
+
};
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error("Error signing transaction:", error);
|
|
99
|
+
throw new Error(`Failed to sign transaction: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async signAuthEntry(entryXdr, options) {
|
|
103
|
+
try {
|
|
104
|
+
const result = await freighterApi.signAuthEntry(entryXdr, {
|
|
105
|
+
accountToSign: options?.accountToSign
|
|
106
|
+
});
|
|
107
|
+
if (!result || typeof result !== "string") {
|
|
108
|
+
throw new Error("Invalid response from Freighter");
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
signedAuthEntry: result
|
|
112
|
+
};
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error("Error signing auth entry:", error);
|
|
115
|
+
throw new Error(`Failed to sign auth entry: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/utils/balanceUtils.ts
|
|
121
|
+
var HORIZON_URLS = {
|
|
122
|
+
PUBLIC: "https://horizon.stellar.org",
|
|
123
|
+
TESTNET: "https://horizon-testnet.stellar.org",
|
|
124
|
+
FUTURENET: "https://horizon-futurenet.stellar.org",
|
|
125
|
+
STANDALONE: "http://localhost:8000"
|
|
126
|
+
};
|
|
127
|
+
async function fetchAccountBalances(publicKey, network) {
|
|
128
|
+
const horizonUrl = HORIZON_URLS[network];
|
|
129
|
+
try {
|
|
130
|
+
const response = await fetch(`${horizonUrl}/accounts/${publicKey}`);
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
if (response.status === 404) {
|
|
133
|
+
throw new Error("Account not found. Make sure the account is funded.");
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`Failed to fetch account: ${response.statusText}`);
|
|
136
|
+
}
|
|
137
|
+
const data = await response.json();
|
|
138
|
+
return data.balances;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error("Error fetching balances:", error);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function getNativeBalance(balances) {
|
|
145
|
+
const nativeBalance = balances.find((b) => b.asset_type === "native");
|
|
146
|
+
return nativeBalance?.balance || "0";
|
|
147
|
+
}
|
|
148
|
+
function formatBalance(balance, decimals = 7) {
|
|
149
|
+
const num = parseFloat(balance);
|
|
150
|
+
if (isNaN(num)) return "0";
|
|
151
|
+
return num.toFixed(decimals).replace(/\.?0+$/, "");
|
|
152
|
+
}
|
|
153
|
+
function getAssetBalance(balances, assetCode, assetIssuer) {
|
|
154
|
+
if (!assetCode) {
|
|
155
|
+
return getNativeBalance(balances);
|
|
156
|
+
}
|
|
157
|
+
const asset = balances.find(
|
|
158
|
+
(b) => b.asset_code === assetCode && (!assetIssuer || b.asset_issuer === assetIssuer)
|
|
159
|
+
);
|
|
160
|
+
return asset?.balance || "0";
|
|
161
|
+
}
|
|
162
|
+
function hasSufficientBalance(balances, requiredAmount, assetCode, assetIssuer) {
|
|
163
|
+
const balance = getAssetBalance(balances, assetCode, assetIssuer);
|
|
164
|
+
return parseFloat(balance) >= parseFloat(requiredAmount);
|
|
165
|
+
}
|
|
166
|
+
function getTotalValueXLM(balances) {
|
|
167
|
+
return getNativeBalance(balances);
|
|
168
|
+
}
|
|
169
|
+
function groupBalancesByType(balances) {
|
|
170
|
+
return balances.reduce((acc, balance) => {
|
|
171
|
+
const type = balance.asset_type;
|
|
172
|
+
if (!acc[type]) {
|
|
173
|
+
acc[type] = [];
|
|
174
|
+
}
|
|
175
|
+
acc[type].push(balance);
|
|
176
|
+
return acc;
|
|
177
|
+
}, {});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/context/WalletContext.tsx
|
|
181
|
+
var WalletContext = React3.createContext(void 0);
|
|
182
|
+
var STORAGE_KEY = "stellar_wallet_kit";
|
|
183
|
+
var getStorageData = () => {
|
|
184
|
+
if (typeof window === "undefined") {
|
|
185
|
+
return { selectedWallet: null, autoConnect: false };
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const data = localStorage.getItem(STORAGE_KEY);
|
|
189
|
+
return data ? JSON.parse(data) : { selectedWallet: null, autoConnect: false };
|
|
190
|
+
} catch {
|
|
191
|
+
return { selectedWallet: null, autoConnect: false };
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
var setStorageData = (data) => {
|
|
195
|
+
if (typeof window === "undefined") return;
|
|
196
|
+
try {
|
|
197
|
+
const existing = getStorageData();
|
|
198
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify({ ...existing, ...data }));
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error("Failed to save to localStorage:", error);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
var isBrowser = typeof window !== "undefined";
|
|
204
|
+
var walletAdapters = {
|
|
205
|
+
["freighter" /* FREIGHTER */]: new FreighterAdapter()
|
|
206
|
+
};
|
|
207
|
+
var walletMetadata = {
|
|
208
|
+
["freighter" /* FREIGHTER */]: {
|
|
209
|
+
id: "freighter" /* FREIGHTER */,
|
|
210
|
+
name: "Freighter",
|
|
211
|
+
icon: "https://stellar.creit.tech/wallet-icons/freighter.svg",
|
|
212
|
+
description: "Freighter browser extension wallet",
|
|
213
|
+
downloadUrl: "https://chrome.google.com/webstore/detail/freighter/bcacfldlkkdogcmkkibnjlakofdplcbk"
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function WalletProvider({ config = {}, children }) {
|
|
217
|
+
const [account, setAccount] = React3.useState(null);
|
|
218
|
+
const [isConnecting, setIsConnecting] = React3.useState(false);
|
|
219
|
+
const [error, setError] = React3.useState(null);
|
|
220
|
+
const [network, setNetwork] = React3.useState(config.network || "TESTNET" /* TESTNET */);
|
|
221
|
+
const [selectedWallet, setSelectedWallet] = React3.useState(null);
|
|
222
|
+
const [availableWallets, setAvailableWallets] = React3.useState([]);
|
|
223
|
+
const [isLoadingBalances, setIsLoadingBalances] = React3.useState(false);
|
|
224
|
+
const isConnected2 = !!account;
|
|
225
|
+
React3.useEffect(() => {
|
|
226
|
+
if (!isBrowser) return;
|
|
227
|
+
const checkWallets = async () => {
|
|
228
|
+
const wallets = [];
|
|
229
|
+
for (const [type, adapter] of Object.entries(walletAdapters)) {
|
|
230
|
+
const installed = await adapter.isAvailable();
|
|
231
|
+
wallets.push({
|
|
232
|
+
...walletMetadata[type],
|
|
233
|
+
installed
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
setAvailableWallets(wallets);
|
|
237
|
+
};
|
|
238
|
+
checkWallets();
|
|
239
|
+
}, []);
|
|
240
|
+
React3.useEffect(() => {
|
|
241
|
+
if (!isBrowser) return;
|
|
242
|
+
const autoConnectWallet = async () => {
|
|
243
|
+
const storage = getStorageData();
|
|
244
|
+
if (config.autoConnect && storage.selectedWallet) {
|
|
245
|
+
try {
|
|
246
|
+
await connect(storage.selectedWallet);
|
|
247
|
+
} catch (err) {
|
|
248
|
+
console.error("Auto-connect failed:", err);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
autoConnectWallet();
|
|
253
|
+
}, [config.autoConnect]);
|
|
254
|
+
const refreshBalances = React3.useCallback(async () => {
|
|
255
|
+
if (!account?.publicKey) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
setIsLoadingBalances(true);
|
|
259
|
+
try {
|
|
260
|
+
const balances = await fetchAccountBalances(account.publicKey, network);
|
|
261
|
+
setAccount((prev) => prev ? { ...prev, balances } : null);
|
|
262
|
+
} catch (err) {
|
|
263
|
+
console.error("Failed to fetch balances:", err);
|
|
264
|
+
} finally {
|
|
265
|
+
setIsLoadingBalances(false);
|
|
266
|
+
}
|
|
267
|
+
}, [account?.publicKey, network]);
|
|
268
|
+
const connect = React3.useCallback(async (walletType) => {
|
|
269
|
+
setIsConnecting(true);
|
|
270
|
+
setError(null);
|
|
271
|
+
try {
|
|
272
|
+
const typeToConnect = walletType || config.defaultWallet || "freighter" /* FREIGHTER */;
|
|
273
|
+
const adapter = walletAdapters[typeToConnect];
|
|
274
|
+
if (!adapter) {
|
|
275
|
+
throw new Error(`Wallet adapter not found for ${typeToConnect}`);
|
|
276
|
+
}
|
|
277
|
+
const available = await adapter.isAvailable();
|
|
278
|
+
if (!available) {
|
|
279
|
+
throw new Error(`${walletMetadata[typeToConnect].name} is not installed`);
|
|
280
|
+
}
|
|
281
|
+
const response = await adapter.connect();
|
|
282
|
+
const newAccount = {
|
|
283
|
+
address: response.address,
|
|
284
|
+
publicKey: response.publicKey,
|
|
285
|
+
displayName: `${response.address.slice(0, 4)}...${response.address.slice(-4)}`
|
|
286
|
+
};
|
|
287
|
+
setAccount(newAccount);
|
|
288
|
+
setSelectedWallet(typeToConnect);
|
|
289
|
+
setStorageData({ selectedWallet: typeToConnect, autoConnect: true });
|
|
290
|
+
try {
|
|
291
|
+
const balances = await fetchAccountBalances(response.publicKey, network);
|
|
292
|
+
setAccount((prev) => prev ? { ...prev, balances } : null);
|
|
293
|
+
} catch (balanceError) {
|
|
294
|
+
console.error("Failed to fetch initial balances:", balanceError);
|
|
295
|
+
}
|
|
296
|
+
} catch (err) {
|
|
297
|
+
const error2 = err instanceof Error ? err : new Error("Failed to connect wallet");
|
|
298
|
+
setError(error2);
|
|
299
|
+
throw error2;
|
|
300
|
+
} finally {
|
|
301
|
+
setIsConnecting(false);
|
|
302
|
+
}
|
|
303
|
+
}, [config.defaultWallet]);
|
|
304
|
+
const disconnect = React3.useCallback(async () => {
|
|
305
|
+
try {
|
|
306
|
+
if (selectedWallet) {
|
|
307
|
+
const adapter = walletAdapters[selectedWallet];
|
|
308
|
+
await adapter.disconnect();
|
|
309
|
+
}
|
|
310
|
+
setAccount(null);
|
|
311
|
+
setSelectedWallet(null);
|
|
312
|
+
setError(null);
|
|
313
|
+
setStorageData({ selectedWallet: null, autoConnect: false });
|
|
314
|
+
} catch (err) {
|
|
315
|
+
const error2 = err instanceof Error ? err : new Error("Failed to disconnect wallet");
|
|
316
|
+
setError(error2);
|
|
317
|
+
throw error2;
|
|
318
|
+
}
|
|
319
|
+
}, [selectedWallet]);
|
|
320
|
+
const signTransaction2 = React3.useCallback(async (xdr, options) => {
|
|
321
|
+
if (!selectedWallet) {
|
|
322
|
+
throw new Error("No wallet connected");
|
|
323
|
+
}
|
|
324
|
+
const adapter = walletAdapters[selectedWallet];
|
|
325
|
+
return adapter.signTransaction(xdr, options);
|
|
326
|
+
}, [selectedWallet]);
|
|
327
|
+
const signAuthEntry2 = React3.useCallback(async (entryXdr, options) => {
|
|
328
|
+
if (!selectedWallet) {
|
|
329
|
+
throw new Error("No wallet connected");
|
|
330
|
+
}
|
|
331
|
+
const adapter = walletAdapters[selectedWallet];
|
|
332
|
+
return adapter.signAuthEntry(entryXdr, options);
|
|
333
|
+
}, [selectedWallet]);
|
|
334
|
+
const switchNetwork = React3.useCallback(async (newNetwork) => {
|
|
335
|
+
setNetwork(newNetwork);
|
|
336
|
+
if (account?.publicKey) {
|
|
337
|
+
await refreshBalances();
|
|
338
|
+
}
|
|
339
|
+
}, [account?.publicKey, refreshBalances]);
|
|
340
|
+
React3.useEffect(() => {
|
|
341
|
+
if (!account?.publicKey || !isBrowser) return;
|
|
342
|
+
refreshBalances();
|
|
343
|
+
const interval = setInterval(() => {
|
|
344
|
+
refreshBalances();
|
|
345
|
+
}, 3e4);
|
|
346
|
+
return () => clearInterval(interval);
|
|
347
|
+
}, [account?.publicKey, refreshBalances]);
|
|
348
|
+
const value = React3.useMemo(
|
|
349
|
+
() => ({
|
|
350
|
+
account,
|
|
351
|
+
isConnected: isConnected2,
|
|
352
|
+
isConnecting,
|
|
353
|
+
error,
|
|
354
|
+
network,
|
|
355
|
+
selectedWallet,
|
|
356
|
+
connect,
|
|
357
|
+
disconnect,
|
|
358
|
+
signTransaction: signTransaction2,
|
|
359
|
+
signAuthEntry: signAuthEntry2,
|
|
360
|
+
switchNetwork,
|
|
361
|
+
availableWallets,
|
|
362
|
+
refreshBalances,
|
|
363
|
+
isLoadingBalances
|
|
364
|
+
}),
|
|
365
|
+
[
|
|
366
|
+
account,
|
|
367
|
+
isConnected2,
|
|
368
|
+
isConnecting,
|
|
369
|
+
error,
|
|
370
|
+
network,
|
|
371
|
+
selectedWallet,
|
|
372
|
+
connect,
|
|
373
|
+
disconnect,
|
|
374
|
+
signTransaction2,
|
|
375
|
+
signAuthEntry2,
|
|
376
|
+
switchNetwork,
|
|
377
|
+
availableWallets,
|
|
378
|
+
refreshBalances,
|
|
379
|
+
isLoadingBalances
|
|
380
|
+
]
|
|
381
|
+
);
|
|
382
|
+
return /* @__PURE__ */ React3__default.default.createElement(WalletContext.Provider, { value }, children);
|
|
383
|
+
}
|
|
384
|
+
function useWallet() {
|
|
385
|
+
const context = React3.useContext(WalletContext);
|
|
386
|
+
if (context === void 0) {
|
|
387
|
+
throw new Error("useWallet must be used within a WalletProvider");
|
|
388
|
+
}
|
|
389
|
+
return context;
|
|
390
|
+
}
|
|
391
|
+
function WalletModal({
|
|
392
|
+
isOpen,
|
|
393
|
+
onClose,
|
|
394
|
+
wallets,
|
|
395
|
+
onSelectWallet,
|
|
396
|
+
theme,
|
|
397
|
+
appName = "Your App",
|
|
398
|
+
appIcon
|
|
399
|
+
}) {
|
|
400
|
+
React3.useEffect(() => {
|
|
401
|
+
const handleEsc = (e) => {
|
|
402
|
+
if (e.key === "Escape") onClose();
|
|
403
|
+
};
|
|
404
|
+
if (isOpen) {
|
|
405
|
+
document.addEventListener("keydown", handleEsc);
|
|
406
|
+
document.body.style.overflow = "hidden";
|
|
407
|
+
}
|
|
408
|
+
return () => {
|
|
409
|
+
document.removeEventListener("keydown", handleEsc);
|
|
410
|
+
document.body.style.overflow = "unset";
|
|
411
|
+
};
|
|
412
|
+
}, [isOpen, onClose]);
|
|
413
|
+
if (!isOpen) return null;
|
|
414
|
+
const themeMode = theme?.mode || "light";
|
|
415
|
+
const isDark = themeMode === "dark" || themeMode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
416
|
+
const styles = {
|
|
417
|
+
overlay: {
|
|
418
|
+
position: "fixed",
|
|
419
|
+
top: 0,
|
|
420
|
+
left: 0,
|
|
421
|
+
right: 0,
|
|
422
|
+
bottom: 0,
|
|
423
|
+
backgroundColor: theme?.overlayBackground || (isDark ? "rgba(0, 0, 0, 0.8)" : "rgba(0, 0, 0, 0.5)"),
|
|
424
|
+
display: "flex",
|
|
425
|
+
alignItems: "center",
|
|
426
|
+
justifyContent: "center",
|
|
427
|
+
zIndex: 9999,
|
|
428
|
+
animation: "swk-fade-in 0.2s ease-out"
|
|
429
|
+
},
|
|
430
|
+
modal: {
|
|
431
|
+
backgroundColor: theme?.modalBackground || (isDark ? "#1a1a1a" : "#ffffff"),
|
|
432
|
+
borderRadius: theme?.borderRadius || "16px",
|
|
433
|
+
padding: "24px",
|
|
434
|
+
maxWidth: "420px",
|
|
435
|
+
width: "90%",
|
|
436
|
+
maxHeight: "80vh",
|
|
437
|
+
overflowY: "auto",
|
|
438
|
+
boxShadow: isDark ? "0 8px 32px rgba(0, 0, 0, 0.4)" : "0 8px 32px rgba(0, 0, 0, 0.1)",
|
|
439
|
+
animation: "swk-slide-up 0.3s ease-out",
|
|
440
|
+
fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
441
|
+
},
|
|
442
|
+
header: {
|
|
443
|
+
display: "flex",
|
|
444
|
+
alignItems: "center",
|
|
445
|
+
justifyContent: "space-between",
|
|
446
|
+
marginBottom: "24px"
|
|
447
|
+
},
|
|
448
|
+
title: {
|
|
449
|
+
fontSize: "20px",
|
|
450
|
+
fontWeight: 600,
|
|
451
|
+
color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
|
|
452
|
+
margin: 0,
|
|
453
|
+
display: "flex",
|
|
454
|
+
alignItems: "center",
|
|
455
|
+
gap: "12px"
|
|
456
|
+
},
|
|
457
|
+
closeButton: {
|
|
458
|
+
background: "none",
|
|
459
|
+
border: "none",
|
|
460
|
+
fontSize: "24px",
|
|
461
|
+
cursor: "pointer",
|
|
462
|
+
padding: "4px",
|
|
463
|
+
color: theme?.textColor || (isDark ? "#888888" : "#666666"),
|
|
464
|
+
transition: "color 0.2s",
|
|
465
|
+
lineHeight: 1
|
|
466
|
+
},
|
|
467
|
+
walletList: {
|
|
468
|
+
display: "flex",
|
|
469
|
+
flexDirection: "column",
|
|
470
|
+
gap: "12px"
|
|
471
|
+
},
|
|
472
|
+
walletButton: {
|
|
473
|
+
display: "flex",
|
|
474
|
+
alignItems: "center",
|
|
475
|
+
gap: "16px",
|
|
476
|
+
padding: "16px",
|
|
477
|
+
border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
|
|
478
|
+
borderRadius: theme?.borderRadius || "12px",
|
|
479
|
+
background: "none",
|
|
480
|
+
cursor: "pointer",
|
|
481
|
+
transition: "all 0.2s",
|
|
482
|
+
width: "100%",
|
|
483
|
+
textAlign: "left",
|
|
484
|
+
fontFamily: "inherit"
|
|
485
|
+
},
|
|
486
|
+
walletIcon: {
|
|
487
|
+
width: "40px",
|
|
488
|
+
height: "40px",
|
|
489
|
+
borderRadius: "8px",
|
|
490
|
+
flexShrink: 0
|
|
491
|
+
},
|
|
492
|
+
walletInfo: {
|
|
493
|
+
flex: 1
|
|
494
|
+
},
|
|
495
|
+
walletName: {
|
|
496
|
+
fontSize: "16px",
|
|
497
|
+
fontWeight: 500,
|
|
498
|
+
color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
|
|
499
|
+
margin: 0,
|
|
500
|
+
marginBottom: "4px"
|
|
501
|
+
},
|
|
502
|
+
walletDescription: {
|
|
503
|
+
fontSize: "13px",
|
|
504
|
+
color: theme?.textColor || (isDark ? "#888888" : "#666666"),
|
|
505
|
+
margin: 0
|
|
506
|
+
},
|
|
507
|
+
badge: {
|
|
508
|
+
padding: "4px 8px",
|
|
509
|
+
borderRadius: "6px",
|
|
510
|
+
fontSize: "12px",
|
|
511
|
+
fontWeight: 500,
|
|
512
|
+
flexShrink: 0
|
|
513
|
+
},
|
|
514
|
+
installedBadge: {
|
|
515
|
+
backgroundColor: theme?.primaryColor || (isDark ? "#4CAF50" : "#4CAF50"),
|
|
516
|
+
color: "#ffffff"
|
|
517
|
+
},
|
|
518
|
+
notInstalledBadge: {
|
|
519
|
+
backgroundColor: isDark ? "#333333" : "#f0f0f0",
|
|
520
|
+
color: isDark ? "#888888" : "#666666"
|
|
521
|
+
},
|
|
522
|
+
footer: {
|
|
523
|
+
marginTop: "24px",
|
|
524
|
+
paddingTop: "16px",
|
|
525
|
+
borderTop: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
|
|
526
|
+
fontSize: "13px",
|
|
527
|
+
color: isDark ? "#888888" : "#666666",
|
|
528
|
+
textAlign: "center"
|
|
529
|
+
},
|
|
530
|
+
link: {
|
|
531
|
+
color: theme?.primaryColor || "#8b5cf6",
|
|
532
|
+
textDecoration: "none"
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
const handleWalletClick = (wallet) => {
|
|
536
|
+
if (wallet.installed) {
|
|
537
|
+
onSelectWallet(wallet.id);
|
|
538
|
+
} else if (wallet.downloadUrl) {
|
|
539
|
+
window.open(wallet.downloadUrl, "_blank");
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
return /* @__PURE__ */ React3__default.default.createElement(React3__default.default.Fragment, null, /* @__PURE__ */ React3__default.default.createElement("style", null, `
|
|
543
|
+
@keyframes swk-fade-in {
|
|
544
|
+
from { opacity: 0; }
|
|
545
|
+
to { opacity: 1; }
|
|
546
|
+
}
|
|
547
|
+
@keyframes swk-slide-up {
|
|
548
|
+
from {
|
|
549
|
+
opacity: 0;
|
|
550
|
+
transform: translateY(20px);
|
|
551
|
+
}
|
|
552
|
+
to {
|
|
553
|
+
opacity: 1;
|
|
554
|
+
transform: translateY(0);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
.swk-wallet-button:hover {
|
|
558
|
+
background-color: ${theme?.buttonHoverColor || (isDark ? "#252525" : "#f5f5f5")} !important;
|
|
559
|
+
border-color: ${theme?.primaryColor || "#8b5cf6"} !important;
|
|
560
|
+
}
|
|
561
|
+
.swk-close-button:hover {
|
|
562
|
+
color: ${theme?.primaryColor || "#8b5cf6"} !important;
|
|
563
|
+
}
|
|
564
|
+
`), /* @__PURE__ */ React3__default.default.createElement("div", { style: styles.overlay, onClick: onClose }, /* @__PURE__ */ React3__default.default.createElement("div", { style: styles.modal, onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ React3__default.default.createElement("div", { style: styles.header }, /* @__PURE__ */ React3__default.default.createElement("h2", { style: styles.title }, appIcon && /* @__PURE__ */ React3__default.default.createElement("img", { src: appIcon, alt: "", style: { width: "32px", height: "32px", borderRadius: "8px" } }), "Connect Wallet"), /* @__PURE__ */ React3__default.default.createElement(
|
|
565
|
+
"button",
|
|
566
|
+
{
|
|
567
|
+
className: "swk-close-button",
|
|
568
|
+
style: styles.closeButton,
|
|
569
|
+
onClick: onClose,
|
|
570
|
+
"aria-label": "Close modal"
|
|
571
|
+
},
|
|
572
|
+
"\xD7"
|
|
573
|
+
)), /* @__PURE__ */ React3__default.default.createElement("div", { style: styles.walletList }, wallets.map((wallet) => /* @__PURE__ */ React3__default.default.createElement(
|
|
574
|
+
"button",
|
|
575
|
+
{
|
|
576
|
+
key: wallet.id,
|
|
577
|
+
className: "swk-wallet-button",
|
|
578
|
+
style: styles.walletButton,
|
|
579
|
+
onClick: () => handleWalletClick(wallet),
|
|
580
|
+
disabled: !wallet.installed && !wallet.downloadUrl
|
|
581
|
+
},
|
|
582
|
+
/* @__PURE__ */ React3__default.default.createElement(
|
|
583
|
+
"img",
|
|
584
|
+
{
|
|
585
|
+
src: wallet.icon,
|
|
586
|
+
alt: `${wallet.name} icon`,
|
|
587
|
+
style: styles.walletIcon
|
|
588
|
+
}
|
|
589
|
+
),
|
|
590
|
+
/* @__PURE__ */ React3__default.default.createElement("div", { style: styles.walletInfo }, /* @__PURE__ */ React3__default.default.createElement("p", { style: styles.walletName }, wallet.name), wallet.description && /* @__PURE__ */ React3__default.default.createElement("p", { style: styles.walletDescription }, wallet.description)),
|
|
591
|
+
/* @__PURE__ */ React3__default.default.createElement(
|
|
592
|
+
"div",
|
|
593
|
+
{
|
|
594
|
+
style: {
|
|
595
|
+
...styles.badge,
|
|
596
|
+
...wallet.installed ? styles.installedBadge : styles.notInstalledBadge
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
wallet.installed ? "Installed" : "Get"
|
|
600
|
+
)
|
|
601
|
+
))), /* @__PURE__ */ React3__default.default.createElement("div", { style: styles.footer }, /* @__PURE__ */ React3__default.default.createElement("p", { style: { margin: 0 } }, "Don't have a wallet?", " ", /* @__PURE__ */ React3__default.default.createElement(
|
|
602
|
+
"a",
|
|
603
|
+
{
|
|
604
|
+
href: "https://www.stellar.org/ecosystem/projects#wallets",
|
|
605
|
+
target: "_blank",
|
|
606
|
+
rel: "noopener noreferrer",
|
|
607
|
+
style: styles.link
|
|
608
|
+
},
|
|
609
|
+
"Learn more"
|
|
610
|
+
))))));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/components/ConnectButton.tsx
|
|
614
|
+
function ConnectButton({
|
|
615
|
+
label = "Connect Wallet",
|
|
616
|
+
theme,
|
|
617
|
+
className,
|
|
618
|
+
style,
|
|
619
|
+
showBalance = false,
|
|
620
|
+
onConnect,
|
|
621
|
+
onDisconnect
|
|
622
|
+
}) {
|
|
623
|
+
const {
|
|
624
|
+
account,
|
|
625
|
+
isConnected: isConnected2,
|
|
626
|
+
isConnecting,
|
|
627
|
+
connect,
|
|
628
|
+
disconnect,
|
|
629
|
+
availableWallets,
|
|
630
|
+
selectedWallet,
|
|
631
|
+
refreshBalances,
|
|
632
|
+
isLoadingBalances
|
|
633
|
+
} = useWallet();
|
|
634
|
+
const [isModalOpen, setIsModalOpen] = React3.useState(false);
|
|
635
|
+
const [showDropdown, setShowDropdown] = React3.useState(false);
|
|
636
|
+
const themeMode = theme?.mode || "light";
|
|
637
|
+
const isDark = themeMode === "dark" || themeMode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
638
|
+
const defaultButtonStyles = {
|
|
639
|
+
padding: "12px 24px",
|
|
640
|
+
borderRadius: theme?.borderRadius || "12px",
|
|
641
|
+
border: "none",
|
|
642
|
+
fontSize: "15px",
|
|
643
|
+
fontWeight: 500,
|
|
644
|
+
cursor: "pointer",
|
|
645
|
+
transition: "all 0.2s",
|
|
646
|
+
fontFamily: theme?.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
647
|
+
...style
|
|
648
|
+
};
|
|
649
|
+
const connectButtonStyles = {
|
|
650
|
+
...defaultButtonStyles,
|
|
651
|
+
backgroundColor: theme?.primaryColor || "#8b5cf6",
|
|
652
|
+
color: "#ffffff"
|
|
653
|
+
};
|
|
654
|
+
const accountButtonStyles = {
|
|
655
|
+
...defaultButtonStyles,
|
|
656
|
+
backgroundColor: isDark ? "#252525" : "#f5f5f5",
|
|
657
|
+
color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
|
|
658
|
+
border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
|
|
659
|
+
position: "relative",
|
|
660
|
+
display: "flex",
|
|
661
|
+
alignItems: "center",
|
|
662
|
+
gap: "8px"
|
|
663
|
+
};
|
|
664
|
+
const dropdownStyles = {
|
|
665
|
+
position: "absolute",
|
|
666
|
+
top: "calc(100% + 8px)",
|
|
667
|
+
right: 0,
|
|
668
|
+
backgroundColor: theme?.modalBackground || (isDark ? "#1a1a1a" : "#ffffff"),
|
|
669
|
+
border: `1px solid ${isDark ? "#333333" : "#e5e5e5"}`,
|
|
670
|
+
borderRadius: theme?.borderRadius || "12px",
|
|
671
|
+
padding: "8px",
|
|
672
|
+
minWidth: "200px",
|
|
673
|
+
boxShadow: isDark ? "0 4px 16px rgba(0, 0, 0, 0.4)" : "0 4px 16px rgba(0, 0, 0, 0.1)",
|
|
674
|
+
zIndex: 1e3
|
|
675
|
+
};
|
|
676
|
+
const dropdownItemStyles = {
|
|
677
|
+
padding: "12px 16px",
|
|
678
|
+
border: "none",
|
|
679
|
+
background: "none",
|
|
680
|
+
cursor: "pointer",
|
|
681
|
+
width: "100%",
|
|
682
|
+
textAlign: "left",
|
|
683
|
+
fontSize: "14px",
|
|
684
|
+
color: theme?.textColor || (isDark ? "#ffffff" : "#000000"),
|
|
685
|
+
borderRadius: "8px",
|
|
686
|
+
transition: "background-color 0.2s",
|
|
687
|
+
fontFamily: "inherit"
|
|
688
|
+
};
|
|
689
|
+
const handleConnect = async (walletType) => {
|
|
690
|
+
try {
|
|
691
|
+
await connect(walletType);
|
|
692
|
+
setIsModalOpen(false);
|
|
693
|
+
onConnect?.();
|
|
694
|
+
} catch (error) {
|
|
695
|
+
console.error("Connection error:", error);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
const handleDisconnect = async () => {
|
|
699
|
+
try {
|
|
700
|
+
await disconnect();
|
|
701
|
+
setShowDropdown(false);
|
|
702
|
+
onDisconnect?.();
|
|
703
|
+
} catch (error) {
|
|
704
|
+
console.error("Disconnect error:", error);
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
const copyAddress = () => {
|
|
708
|
+
if (account?.address) {
|
|
709
|
+
navigator.clipboard.writeText(account.address);
|
|
710
|
+
setShowDropdown(false);
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
if (isConnecting) {
|
|
714
|
+
return /* @__PURE__ */ React3__default.default.createElement(
|
|
715
|
+
"button",
|
|
716
|
+
{
|
|
717
|
+
className,
|
|
718
|
+
style: connectButtonStyles,
|
|
719
|
+
disabled: true
|
|
720
|
+
},
|
|
721
|
+
"Connecting..."
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
if (!isConnected2 || !account) {
|
|
725
|
+
return /* @__PURE__ */ React3__default.default.createElement(React3__default.default.Fragment, null, /* @__PURE__ */ React3__default.default.createElement(
|
|
726
|
+
"button",
|
|
727
|
+
{
|
|
728
|
+
className,
|
|
729
|
+
style: connectButtonStyles,
|
|
730
|
+
onClick: () => setIsModalOpen(true)
|
|
731
|
+
},
|
|
732
|
+
label
|
|
733
|
+
), /* @__PURE__ */ React3__default.default.createElement(
|
|
734
|
+
WalletModal,
|
|
735
|
+
{
|
|
736
|
+
isOpen: isModalOpen,
|
|
737
|
+
onClose: () => setIsModalOpen(false),
|
|
738
|
+
wallets: availableWallets,
|
|
739
|
+
onSelectWallet: handleConnect,
|
|
740
|
+
theme
|
|
741
|
+
}
|
|
742
|
+
));
|
|
743
|
+
}
|
|
744
|
+
const walletIcon = availableWallets.find((w) => w.id === selectedWallet)?.icon;
|
|
745
|
+
const nativeBalance = account?.balances ? getNativeBalance(account.balances) : null;
|
|
746
|
+
const formattedBalance = nativeBalance ? formatBalance(nativeBalance, 2) : null;
|
|
747
|
+
return /* @__PURE__ */ React3__default.default.createElement(React3__default.default.Fragment, null, /* @__PURE__ */ React3__default.default.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React3__default.default.createElement(
|
|
748
|
+
"button",
|
|
749
|
+
{
|
|
750
|
+
className,
|
|
751
|
+
style: accountButtonStyles,
|
|
752
|
+
onClick: () => setShowDropdown(!showDropdown)
|
|
753
|
+
},
|
|
754
|
+
walletIcon && /* @__PURE__ */ React3__default.default.createElement(
|
|
755
|
+
"img",
|
|
756
|
+
{
|
|
757
|
+
src: walletIcon,
|
|
758
|
+
alt: "Wallet",
|
|
759
|
+
style: { width: "20px", height: "20px", borderRadius: "4px" }
|
|
760
|
+
}
|
|
761
|
+
),
|
|
762
|
+
/* @__PURE__ */ React3__default.default.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "2px" } }, /* @__PURE__ */ React3__default.default.createElement("span", null, account.displayName), showBalance && formattedBalance && /* @__PURE__ */ React3__default.default.createElement("span", { style: { fontSize: "12px", opacity: 0.7, fontWeight: 400 } }, isLoadingBalances ? "..." : `${formattedBalance} XLM`)),
|
|
763
|
+
/* @__PURE__ */ React3__default.default.createElement("span", { style: { fontSize: "12px", opacity: 0.7 } }, "\u25BC")
|
|
764
|
+
), showDropdown && /* @__PURE__ */ React3__default.default.createElement(React3__default.default.Fragment, null, /* @__PURE__ */ React3__default.default.createElement(
|
|
765
|
+
"div",
|
|
766
|
+
{
|
|
767
|
+
style: {
|
|
768
|
+
position: "fixed",
|
|
769
|
+
top: 0,
|
|
770
|
+
left: 0,
|
|
771
|
+
right: 0,
|
|
772
|
+
bottom: 0,
|
|
773
|
+
zIndex: 999
|
|
774
|
+
},
|
|
775
|
+
onClick: () => setShowDropdown(false)
|
|
776
|
+
}
|
|
777
|
+
), /* @__PURE__ */ React3__default.default.createElement("div", { style: dropdownStyles }, /* @__PURE__ */ React3__default.default.createElement(
|
|
778
|
+
"button",
|
|
779
|
+
{
|
|
780
|
+
style: dropdownItemStyles,
|
|
781
|
+
onClick: () => {
|
|
782
|
+
refreshBalances();
|
|
783
|
+
setShowDropdown(false);
|
|
784
|
+
},
|
|
785
|
+
onMouseEnter: (e) => {
|
|
786
|
+
e.currentTarget.style.backgroundColor = theme?.buttonHoverColor || (isDark ? "#333333" : "#f0f0f0");
|
|
787
|
+
},
|
|
788
|
+
onMouseLeave: (e) => {
|
|
789
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
790
|
+
}
|
|
791
|
+
},
|
|
792
|
+
"\u{1F504} Refresh Balances"
|
|
793
|
+
), /* @__PURE__ */ React3__default.default.createElement(
|
|
794
|
+
"button",
|
|
795
|
+
{
|
|
796
|
+
style: dropdownItemStyles,
|
|
797
|
+
onClick: copyAddress,
|
|
798
|
+
onMouseEnter: (e) => {
|
|
799
|
+
e.currentTarget.style.backgroundColor = theme?.buttonHoverColor || (isDark ? "#333333" : "#f0f0f0");
|
|
800
|
+
},
|
|
801
|
+
onMouseLeave: (e) => {
|
|
802
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
"\u{1F4CB} Copy Address"
|
|
806
|
+
), /* @__PURE__ */ React3__default.default.createElement(
|
|
807
|
+
"button",
|
|
808
|
+
{
|
|
809
|
+
style: {
|
|
810
|
+
...dropdownItemStyles,
|
|
811
|
+
color: "#ef4444"
|
|
812
|
+
},
|
|
813
|
+
onClick: handleDisconnect,
|
|
814
|
+
onMouseEnter: (e) => {
|
|
815
|
+
e.currentTarget.style.backgroundColor = theme?.buttonHoverColor || (isDark ? "#333333" : "#f0f0f0");
|
|
816
|
+
},
|
|
817
|
+
onMouseLeave: (e) => {
|
|
818
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
"\u{1F6AA} Disconnect"
|
|
822
|
+
)))));
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
exports.ConnectButton = ConnectButton;
|
|
826
|
+
exports.FreighterAdapter = FreighterAdapter;
|
|
827
|
+
exports.NetworkType = NetworkType;
|
|
828
|
+
exports.WalletModal = WalletModal;
|
|
829
|
+
exports.WalletProvider = WalletProvider;
|
|
830
|
+
exports.WalletType = WalletType;
|
|
831
|
+
exports.fetchAccountBalances = fetchAccountBalances;
|
|
832
|
+
exports.formatBalance = formatBalance;
|
|
833
|
+
exports.getAssetBalance = getAssetBalance;
|
|
834
|
+
exports.getNativeBalance = getNativeBalance;
|
|
835
|
+
exports.getTotalValueXLM = getTotalValueXLM;
|
|
836
|
+
exports.groupBalancesByType = groupBalancesByType;
|
|
837
|
+
exports.hasSufficientBalance = hasSufficientBalance;
|
|
838
|
+
exports.useWallet = useWallet;
|
|
839
|
+
//# sourceMappingURL=index.js.map
|
|
840
|
+
//# sourceMappingURL=index.js.map
|