stellar-wallet-kit 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -424
- package/dist/index.d.mts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +246 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +246 -61
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { isConnected, isAllowed, setAllowed, getUserInfo, getNetwork, signTransa
|
|
|
6
6
|
// src/types/index.ts
|
|
7
7
|
var WalletType = /* @__PURE__ */ ((WalletType2) => {
|
|
8
8
|
WalletType2["FREIGHTER"] = "freighter";
|
|
9
|
+
WalletType2["ALBEDO"] = "albedo";
|
|
9
10
|
return WalletType2;
|
|
10
11
|
})(WalletType || {});
|
|
11
12
|
var NetworkType = /* @__PURE__ */ ((NetworkType2) => {
|
|
@@ -171,7 +172,131 @@ function groupBalancesByType(balances) {
|
|
|
171
172
|
}, {});
|
|
172
173
|
}
|
|
173
174
|
|
|
175
|
+
// src/utils/albedoCallback.ts
|
|
176
|
+
function openAlbedoPopup(url) {
|
|
177
|
+
const popup = window.open(
|
|
178
|
+
url,
|
|
179
|
+
"albedo",
|
|
180
|
+
"width=420,height=720,resizable=yes,scrollbars=yes"
|
|
181
|
+
);
|
|
182
|
+
if (!popup) {
|
|
183
|
+
throw new Error("Failed to open Albedo popup (blocked by browser)");
|
|
184
|
+
}
|
|
185
|
+
return popup;
|
|
186
|
+
}
|
|
187
|
+
function waitForAlbedoResult() {
|
|
188
|
+
return new Promise((resolve, reject) => {
|
|
189
|
+
const timeout = setTimeout(() => {
|
|
190
|
+
reject(new Error("Albedo response timeout"));
|
|
191
|
+
}, 2 * 60 * 1e3);
|
|
192
|
+
const parseResult = () => {
|
|
193
|
+
const params = new URLSearchParams(window.location.search);
|
|
194
|
+
if (!params.has("pubkey") && !params.has("signed_envelope_xdr") && !params.has("signed_xdr")) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
clearTimeout(timeout);
|
|
198
|
+
const result = {};
|
|
199
|
+
params.forEach((value, key) => {
|
|
200
|
+
result[key] = value;
|
|
201
|
+
});
|
|
202
|
+
window.history.replaceState({}, document.title, window.location.pathname);
|
|
203
|
+
resolve(result);
|
|
204
|
+
};
|
|
205
|
+
parseResult();
|
|
206
|
+
window.addEventListener("popstate", parseResult);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function waitForAlbedoPopup() {
|
|
210
|
+
return new Promise((resolve, reject) => {
|
|
211
|
+
const timeout = setTimeout(() => {
|
|
212
|
+
reject(new Error("Albedo response timeout"));
|
|
213
|
+
}, 2 * 60 * 1e3);
|
|
214
|
+
function handler(event) {
|
|
215
|
+
if (event.origin !== window.location.origin || event.data?.type !== "ALBEDO_RESULT") {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
clearTimeout(timeout);
|
|
219
|
+
window.removeEventListener("message", handler);
|
|
220
|
+
resolve(event.data.payload);
|
|
221
|
+
}
|
|
222
|
+
window.addEventListener("message", handler);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/adapters/AlbedoAdapter.ts
|
|
227
|
+
var AlbedoAdapter = class {
|
|
228
|
+
constructor() {
|
|
229
|
+
this.type = "albedo" /* ALBEDO */;
|
|
230
|
+
}
|
|
231
|
+
async isAvailable() {
|
|
232
|
+
return typeof window !== "undefined";
|
|
233
|
+
}
|
|
234
|
+
async connect() {
|
|
235
|
+
const url = new URL("https://albedo.link");
|
|
236
|
+
url.searchParams.set("intent", "public-key");
|
|
237
|
+
url.searchParams.set("app_name", "Stellar Wallet Kit");
|
|
238
|
+
url.searchParams.set("network", "testnet");
|
|
239
|
+
url.searchParams.set(
|
|
240
|
+
"callback",
|
|
241
|
+
`${window.location.origin}/albedo-callback`
|
|
242
|
+
);
|
|
243
|
+
url.searchParams.set("origin", window.location.origin);
|
|
244
|
+
openAlbedoPopup(url.toString());
|
|
245
|
+
const result = await waitForAlbedoPopup();
|
|
246
|
+
if (!result.pubkey) {
|
|
247
|
+
throw new Error("Albedo connection rejected");
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
address: result.pubkey,
|
|
251
|
+
publicKey: result.pubkey
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
async disconnect() {
|
|
255
|
+
}
|
|
256
|
+
async getPublicKey() {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
async getNetwork() {
|
|
260
|
+
throw new Error("Albedo does not expose network");
|
|
261
|
+
}
|
|
262
|
+
async signTransaction(xdr, _options) {
|
|
263
|
+
const url = new URL("https://albedo.link");
|
|
264
|
+
url.searchParams.set("intent", "tx");
|
|
265
|
+
url.searchParams.set("xdr", xdr);
|
|
266
|
+
url.searchParams.set("app_name", "Stellar Wallet Kit");
|
|
267
|
+
url.searchParams.set("network", "testnet");
|
|
268
|
+
url.searchParams.set("callback", window.location.href);
|
|
269
|
+
url.searchParams.set("origin", window.location.origin);
|
|
270
|
+
window.location.href = url.toString();
|
|
271
|
+
const result = await waitForAlbedoResult();
|
|
272
|
+
if (!result.signed_envelope_xdr) {
|
|
273
|
+
throw new Error("Albedo signing rejected");
|
|
274
|
+
}
|
|
275
|
+
return { signedTxXdr: result.signed_envelope_xdr };
|
|
276
|
+
}
|
|
277
|
+
async signAuthEntry(entryXdr, _options) {
|
|
278
|
+
const url = new URL("https://albedo.link");
|
|
279
|
+
url.searchParams.set("intent", "sign-auth-entry");
|
|
280
|
+
url.searchParams.set("xdr", entryXdr);
|
|
281
|
+
url.searchParams.set("app_name", "Stellar Wallet Kit");
|
|
282
|
+
url.searchParams.set("network", "testnet");
|
|
283
|
+
url.searchParams.set("callback", window.location.href);
|
|
284
|
+
url.searchParams.set("origin", window.location.origin);
|
|
285
|
+
window.location.href = url.toString();
|
|
286
|
+
const result = await waitForAlbedoResult();
|
|
287
|
+
if (!result.signed_xdr) {
|
|
288
|
+
throw new Error("Albedo auth entry rejected");
|
|
289
|
+
}
|
|
290
|
+
return { signedAuthEntry: result.signed_xdr };
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
174
294
|
// src/context/WalletContext.tsx
|
|
295
|
+
var DEFAULT_SUPPORTS = {
|
|
296
|
+
silentReconnect: false,
|
|
297
|
+
networkDetection: false,
|
|
298
|
+
authEntrySigning: false
|
|
299
|
+
};
|
|
175
300
|
var WalletContext = createContext(void 0);
|
|
176
301
|
var STORAGE_KEY = "stellar_wallet_kit";
|
|
177
302
|
var getStorageData = () => {
|
|
@@ -196,7 +321,8 @@ var setStorageData = (data) => {
|
|
|
196
321
|
};
|
|
197
322
|
var isBrowser = typeof window !== "undefined";
|
|
198
323
|
var walletAdapters = {
|
|
199
|
-
["freighter" /* FREIGHTER */]: new FreighterAdapter()
|
|
324
|
+
["freighter" /* FREIGHTER */]: new FreighterAdapter(),
|
|
325
|
+
["albedo" /* ALBEDO */]: new AlbedoAdapter()
|
|
200
326
|
};
|
|
201
327
|
var walletMetadata = {
|
|
202
328
|
["freighter" /* FREIGHTER */]: {
|
|
@@ -204,14 +330,34 @@ var walletMetadata = {
|
|
|
204
330
|
name: "Freighter",
|
|
205
331
|
icon: "https://stellar.creit.tech/wallet-icons/freighter.svg",
|
|
206
332
|
description: "Freighter browser extension wallet",
|
|
207
|
-
downloadUrl: "https://chrome.google.com/webstore/detail/freighter/bcacfldlkkdogcmkkibnjlakofdplcbk"
|
|
333
|
+
downloadUrl: "https://chrome.google.com/webstore/detail/freighter/bcacfldlkkdogcmkkibnjlakofdplcbk",
|
|
334
|
+
kind: "extension",
|
|
335
|
+
capabilities: {
|
|
336
|
+
silentReconnect: true,
|
|
337
|
+
networkDetection: true,
|
|
338
|
+
authEntrySigning: true
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
["albedo" /* ALBEDO */]: {
|
|
342
|
+
id: "albedo" /* ALBEDO */,
|
|
343
|
+
name: "Albedo",
|
|
344
|
+
icon: "https://stellar.creit.tech/wallet-icons/albedo.svg",
|
|
345
|
+
description: "Web-based Stellar wallet",
|
|
346
|
+
kind: "web",
|
|
347
|
+
capabilities: {
|
|
348
|
+
silentReconnect: false,
|
|
349
|
+
networkDetection: false,
|
|
350
|
+
authEntrySigning: true
|
|
351
|
+
}
|
|
208
352
|
}
|
|
209
353
|
};
|
|
210
354
|
function WalletProvider({ config = {}, children }) {
|
|
211
355
|
const [account, setAccount] = useState(null);
|
|
212
356
|
const [isConnecting, setIsConnecting] = useState(false);
|
|
213
357
|
const [error, setError] = useState(null);
|
|
214
|
-
const [network, setNetwork] = useState(
|
|
358
|
+
const [network, setNetwork] = useState(
|
|
359
|
+
config.network || "TESTNET" /* TESTNET */
|
|
360
|
+
);
|
|
215
361
|
const [selectedWallet, setSelectedWallet] = useState(null);
|
|
216
362
|
const [availableWallets, setAvailableWallets] = useState([]);
|
|
217
363
|
const [isLoadingBalances, setIsLoadingBalances] = useState(false);
|
|
@@ -221,9 +367,14 @@ function WalletProvider({ config = {}, children }) {
|
|
|
221
367
|
const checkWallets = async () => {
|
|
222
368
|
const wallets = [];
|
|
223
369
|
for (const [type, adapter] of Object.entries(walletAdapters)) {
|
|
224
|
-
const
|
|
370
|
+
const walletType = type;
|
|
371
|
+
const meta = walletMetadata[walletType];
|
|
372
|
+
let installed = true;
|
|
373
|
+
if (meta.kind === "extension") {
|
|
374
|
+
installed = await adapter.isAvailable();
|
|
375
|
+
}
|
|
225
376
|
wallets.push({
|
|
226
|
-
...
|
|
377
|
+
...meta,
|
|
227
378
|
installed
|
|
228
379
|
});
|
|
229
380
|
}
|
|
@@ -259,42 +410,54 @@ function WalletProvider({ config = {}, children }) {
|
|
|
259
410
|
setIsLoadingBalances(false);
|
|
260
411
|
}
|
|
261
412
|
}, [account?.publicKey, network]);
|
|
262
|
-
const connect = useCallback(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const typeToConnect = walletType || config.defaultWallet || "freighter" /* FREIGHTER */;
|
|
267
|
-
const adapter = walletAdapters[typeToConnect];
|
|
268
|
-
if (!adapter) {
|
|
269
|
-
throw new Error(`Wallet adapter not found for ${typeToConnect}`);
|
|
270
|
-
}
|
|
271
|
-
const available = await adapter.isAvailable();
|
|
272
|
-
if (!available) {
|
|
273
|
-
throw new Error(`${walletMetadata[typeToConnect].name} is not installed`);
|
|
274
|
-
}
|
|
275
|
-
const response = await adapter.connect();
|
|
276
|
-
const newAccount = {
|
|
277
|
-
address: response.address,
|
|
278
|
-
publicKey: response.publicKey,
|
|
279
|
-
displayName: `${response.address.slice(0, 4)}...${response.address.slice(-4)}`
|
|
280
|
-
};
|
|
281
|
-
setAccount(newAccount);
|
|
282
|
-
setSelectedWallet(typeToConnect);
|
|
283
|
-
setStorageData({ selectedWallet: typeToConnect, autoConnect: true });
|
|
413
|
+
const connect = useCallback(
|
|
414
|
+
async (walletType) => {
|
|
415
|
+
setIsConnecting(true);
|
|
416
|
+
setError(null);
|
|
284
417
|
try {
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
418
|
+
const typeToConnect = walletType || config.defaultWallet || "freighter" /* FREIGHTER */;
|
|
419
|
+
const adapter = walletAdapters[typeToConnect];
|
|
420
|
+
if (!adapter) {
|
|
421
|
+
throw new Error(`Wallet adapter not found for ${typeToConnect}`);
|
|
422
|
+
}
|
|
423
|
+
const meta = walletMetadata[typeToConnect];
|
|
424
|
+
if (meta.kind === "extension") {
|
|
425
|
+
const available = await adapter.isAvailable();
|
|
426
|
+
if (!available) {
|
|
427
|
+
throw new Error(`${meta.name} is not installed`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const response = await adapter.connect();
|
|
431
|
+
const newAccount = {
|
|
432
|
+
address: response.address,
|
|
433
|
+
publicKey: response.publicKey,
|
|
434
|
+
displayName: `${response.address.slice(
|
|
435
|
+
0,
|
|
436
|
+
4
|
|
437
|
+
)}...${response.address.slice(-4)}`
|
|
438
|
+
};
|
|
439
|
+
setAccount(newAccount);
|
|
440
|
+
setSelectedWallet(typeToConnect);
|
|
441
|
+
setStorageData({ selectedWallet: typeToConnect, autoConnect: true });
|
|
442
|
+
try {
|
|
443
|
+
const balances = await fetchAccountBalances(
|
|
444
|
+
response.publicKey,
|
|
445
|
+
network
|
|
446
|
+
);
|
|
447
|
+
setAccount((prev) => prev ? { ...prev, balances } : null);
|
|
448
|
+
} catch (balanceError) {
|
|
449
|
+
console.error("Failed to fetch initial balances:", balanceError);
|
|
450
|
+
}
|
|
451
|
+
} catch (err) {
|
|
452
|
+
const error2 = err instanceof Error ? err : new Error("Failed to connect wallet");
|
|
453
|
+
setError(error2);
|
|
454
|
+
throw error2;
|
|
455
|
+
} finally {
|
|
456
|
+
setIsConnecting(false);
|
|
289
457
|
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
throw error2;
|
|
294
|
-
} finally {
|
|
295
|
-
setIsConnecting(false);
|
|
296
|
-
}
|
|
297
|
-
}, [config.defaultWallet]);
|
|
458
|
+
},
|
|
459
|
+
[config.defaultWallet]
|
|
460
|
+
);
|
|
298
461
|
const disconnect = useCallback(async () => {
|
|
299
462
|
try {
|
|
300
463
|
if (selectedWallet) {
|
|
@@ -311,26 +474,35 @@ function WalletProvider({ config = {}, children }) {
|
|
|
311
474
|
throw error2;
|
|
312
475
|
}
|
|
313
476
|
}, [selectedWallet]);
|
|
314
|
-
const signTransaction2 = useCallback(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
477
|
+
const signTransaction2 = useCallback(
|
|
478
|
+
async (xdr, options) => {
|
|
479
|
+
if (!selectedWallet) {
|
|
480
|
+
throw new Error("No wallet connected");
|
|
481
|
+
}
|
|
482
|
+
const adapter = walletAdapters[selectedWallet];
|
|
483
|
+
return adapter.signTransaction(xdr, options);
|
|
484
|
+
},
|
|
485
|
+
[selectedWallet]
|
|
486
|
+
);
|
|
487
|
+
const signAuthEntry2 = useCallback(
|
|
488
|
+
async (entryXdr, options) => {
|
|
489
|
+
if (!selectedWallet) {
|
|
490
|
+
throw new Error("No wallet connected");
|
|
491
|
+
}
|
|
492
|
+
const adapter = walletAdapters[selectedWallet];
|
|
493
|
+
return adapter.signAuthEntry(entryXdr, options);
|
|
494
|
+
},
|
|
495
|
+
[selectedWallet]
|
|
496
|
+
);
|
|
497
|
+
const switchNetwork = useCallback(
|
|
498
|
+
async (newNetwork) => {
|
|
499
|
+
setNetwork(newNetwork);
|
|
500
|
+
if (account?.publicKey) {
|
|
501
|
+
await refreshBalances();
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
[account?.publicKey, refreshBalances]
|
|
505
|
+
);
|
|
334
506
|
useEffect(() => {
|
|
335
507
|
if (!account?.publicKey || !isBrowser) return;
|
|
336
508
|
refreshBalances();
|
|
@@ -339,6 +511,17 @@ function WalletProvider({ config = {}, children }) {
|
|
|
339
511
|
}, 3e4);
|
|
340
512
|
return () => clearInterval(interval);
|
|
341
513
|
}, [account?.publicKey, refreshBalances]);
|
|
514
|
+
const supports = useMemo(() => {
|
|
515
|
+
if (!selectedWallet) {
|
|
516
|
+
return DEFAULT_SUPPORTS;
|
|
517
|
+
}
|
|
518
|
+
const meta = walletMetadata[selectedWallet];
|
|
519
|
+
return {
|
|
520
|
+
silentReconnect: !!meta.capabilities?.silentReconnect,
|
|
521
|
+
networkDetection: !!meta.capabilities?.networkDetection,
|
|
522
|
+
authEntrySigning: !!meta.capabilities?.authEntrySigning
|
|
523
|
+
};
|
|
524
|
+
}, [selectedWallet]);
|
|
342
525
|
const value = useMemo(
|
|
343
526
|
() => ({
|
|
344
527
|
account,
|
|
@@ -354,7 +537,8 @@ function WalletProvider({ config = {}, children }) {
|
|
|
354
537
|
switchNetwork,
|
|
355
538
|
availableWallets,
|
|
356
539
|
refreshBalances,
|
|
357
|
-
isLoadingBalances
|
|
540
|
+
isLoadingBalances,
|
|
541
|
+
supports
|
|
358
542
|
}),
|
|
359
543
|
[
|
|
360
544
|
account,
|
|
@@ -370,7 +554,8 @@ function WalletProvider({ config = {}, children }) {
|
|
|
370
554
|
switchNetwork,
|
|
371
555
|
availableWallets,
|
|
372
556
|
refreshBalances,
|
|
373
|
-
isLoadingBalances
|
|
557
|
+
isLoadingBalances,
|
|
558
|
+
supports
|
|
374
559
|
]
|
|
375
560
|
);
|
|
376
561
|
return /* @__PURE__ */ React3.createElement(WalletContext.Provider, { value }, children);
|