@phantom/browser-sdk 1.0.0-beta.8 → 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/README.md +341 -94
- package/dist/index.d.ts +96 -68
- package/dist/index.js +2755 -678
- package/dist/index.mjs +2750 -683
- package/package.json +15 -10
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,12 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var src_exports = {};
|
|
22
32
|
__export(src_exports, {
|
|
23
|
-
AddressType: () =>
|
|
33
|
+
AddressType: () => import_client4.AddressType,
|
|
24
34
|
BrowserSDK: () => BrowserSDK,
|
|
25
35
|
DebugCategory: () => DebugCategory,
|
|
26
36
|
DebugLevel: () => DebugLevel,
|
|
@@ -31,6 +41,7 @@ __export(src_exports, {
|
|
|
31
41
|
getDeeplinkToPhantom: () => getDeeplinkToPhantom,
|
|
32
42
|
getPlatformName: () => getPlatformName,
|
|
33
43
|
isMobileDevice: () => isMobileDevice,
|
|
44
|
+
isPhantomLoginAvailable: () => isPhantomLoginAvailable,
|
|
34
45
|
parseBrowserFromUserAgent: () => parseBrowserFromUserAgent,
|
|
35
46
|
waitForPhantomExtension: () => waitForPhantomExtension
|
|
36
47
|
});
|
|
@@ -40,11 +51,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
40
51
|
var import_client = require("@phantom/client");
|
|
41
52
|
|
|
42
53
|
// src/providers/injected/index.ts
|
|
43
|
-
var
|
|
44
|
-
var import_browser_injected_sdk = require("@phantom/browser-injected-sdk");
|
|
45
|
-
var import_solana = require("@phantom/browser-injected-sdk/solana");
|
|
46
|
-
var import_ethereum = require("@phantom/browser-injected-sdk/ethereum");
|
|
47
|
-
var import_auto_confirm = require("@phantom/browser-injected-sdk/auto-confirm");
|
|
54
|
+
var import_client3 = require("@phantom/client");
|
|
48
55
|
|
|
49
56
|
// src/debug.ts
|
|
50
57
|
var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
|
|
@@ -120,135 +127,604 @@ var DebugCategory = {
|
|
|
120
127
|
SESSION: "Session"
|
|
121
128
|
};
|
|
122
129
|
|
|
123
|
-
// src/
|
|
124
|
-
var import_eventemitter3 = require("eventemitter3");
|
|
130
|
+
// src/wallets/discovery.ts
|
|
125
131
|
var import_client2 = require("@phantom/client");
|
|
132
|
+
var import_browser_injected_sdk = require("@phantom/browser-injected-sdk");
|
|
133
|
+
var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
|
|
134
|
+
var import_solana = require("@phantom/browser-injected-sdk/solana");
|
|
135
|
+
var import_ethereum = require("@phantom/browser-injected-sdk/ethereum");
|
|
136
|
+
var import_auto_confirm = require("@phantom/browser-injected-sdk/auto-confirm");
|
|
137
|
+
function generateWalletIdFromEIP6963(info) {
|
|
138
|
+
if (info.rdns) {
|
|
139
|
+
return info.rdns.split(".").reverse().join("-");
|
|
140
|
+
}
|
|
141
|
+
return info.name.toLowerCase().replace(/\s+/g, "-");
|
|
142
|
+
}
|
|
143
|
+
function generateWalletIdFromName(name) {
|
|
144
|
+
return name.toLowerCase().replace(/\s+/g, "-");
|
|
145
|
+
}
|
|
146
|
+
function processEIP6963Providers(providers) {
|
|
147
|
+
const wallets = [];
|
|
148
|
+
debug.log(DebugCategory.BROWSER_SDK, "Processing EIP-6963 providers", {
|
|
149
|
+
providerCount: providers.size,
|
|
150
|
+
providerNames: Array.from(providers.values()).map((d) => d.info.name)
|
|
151
|
+
});
|
|
152
|
+
for (const [, detail] of providers) {
|
|
153
|
+
const { info, provider } = detail;
|
|
154
|
+
const isPhantom = info.name.toLowerCase().includes("phantom") || info.rdns && (info.rdns.toLowerCase().includes("phantom") || info.rdns.toLowerCase() === "app.phantom");
|
|
155
|
+
if (isPhantom) {
|
|
156
|
+
debug.log(DebugCategory.BROWSER_SDK, "Skipping Phantom from EIP-6963", { name: info.name, rdns: info.rdns });
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const walletId = generateWalletIdFromEIP6963(info);
|
|
160
|
+
debug.log(DebugCategory.BROWSER_SDK, "Discovered EIP-6963 wallet", {
|
|
161
|
+
walletId,
|
|
162
|
+
walletName: info.name,
|
|
163
|
+
rdns: info.rdns
|
|
164
|
+
});
|
|
165
|
+
wallets.push({
|
|
166
|
+
id: walletId,
|
|
167
|
+
name: info.name,
|
|
168
|
+
icon: info.icon,
|
|
169
|
+
addressTypes: [import_client2.AddressType.ethereum],
|
|
170
|
+
providers: {
|
|
171
|
+
// EIP-6963 provider implements EIP-1193 interface (IEthereumChain)
|
|
172
|
+
ethereum: provider
|
|
173
|
+
},
|
|
174
|
+
rdns: info.rdns,
|
|
175
|
+
// Store rdns for potential future matching
|
|
176
|
+
discovery: "eip6963"
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
debug.log(DebugCategory.BROWSER_SDK, "EIP-6963 discovery completed", {
|
|
180
|
+
discoveredCount: wallets.length,
|
|
181
|
+
walletIds: wallets.map((w) => w.id)
|
|
182
|
+
});
|
|
183
|
+
return wallets;
|
|
184
|
+
}
|
|
185
|
+
function discoverEthereumWallets() {
|
|
186
|
+
return new Promise((resolve) => {
|
|
187
|
+
const discoveredProviders = /* @__PURE__ */ new Map();
|
|
188
|
+
if (typeof window === "undefined") {
|
|
189
|
+
resolve([]);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const handleAnnounce = (event) => {
|
|
193
|
+
const detail = event.detail;
|
|
194
|
+
if (detail?.info && detail?.provider) {
|
|
195
|
+
discoveredProviders.set(detail.info.uuid, detail);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
window.addEventListener("eip6963:announceProvider", handleAnnounce);
|
|
199
|
+
window.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
200
|
+
const processProviders = () => {
|
|
201
|
+
const wallets = processEIP6963Providers(discoveredProviders);
|
|
202
|
+
window.removeEventListener("eip6963:announceProvider", handleAnnounce);
|
|
203
|
+
resolve(wallets);
|
|
204
|
+
};
|
|
205
|
+
setTimeout(processProviders, 400);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function discoverSolanaWallets() {
|
|
209
|
+
const wallets = [];
|
|
210
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
211
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard discovery skipped (not in browser environment)");
|
|
212
|
+
return wallets;
|
|
213
|
+
}
|
|
214
|
+
const registeredWalletsSet = /* @__PURE__ */ new Set();
|
|
215
|
+
let cachedWalletsArray;
|
|
216
|
+
function addRegisteredWallet(wallet) {
|
|
217
|
+
cachedWalletsArray = void 0;
|
|
218
|
+
registeredWalletsSet.add(wallet);
|
|
219
|
+
const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
|
|
220
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet registered", {
|
|
221
|
+
name: wallet.name,
|
|
222
|
+
chains: wallet.chains,
|
|
223
|
+
featureKeys,
|
|
224
|
+
totalWallets: registeredWalletsSet.size
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function removeRegisteredWallet(wallet) {
|
|
228
|
+
cachedWalletsArray = void 0;
|
|
229
|
+
registeredWalletsSet.delete(wallet);
|
|
230
|
+
}
|
|
231
|
+
function getRegisteredWallets() {
|
|
232
|
+
if (!cachedWalletsArray) {
|
|
233
|
+
cachedWalletsArray = [...registeredWalletsSet];
|
|
234
|
+
}
|
|
235
|
+
return cachedWalletsArray;
|
|
236
|
+
}
|
|
237
|
+
function register(...wallets2) {
|
|
238
|
+
wallets2 = wallets2.filter((wallet) => !registeredWalletsSet.has(wallet));
|
|
239
|
+
if (!wallets2.length) {
|
|
240
|
+
return () => {
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
wallets2.forEach((wallet) => addRegisteredWallet(wallet));
|
|
244
|
+
return function unregister() {
|
|
245
|
+
wallets2.forEach((wallet) => removeRegisteredWallet(wallet));
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const registerAPI = Object.freeze({ register });
|
|
249
|
+
const handleRegisterWalletEvent = (event) => {
|
|
250
|
+
const callback = event.detail;
|
|
251
|
+
if (typeof callback === "function") {
|
|
252
|
+
try {
|
|
253
|
+
callback(registerAPI);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Error calling wallet registration callback", { error });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
try {
|
|
260
|
+
window.addEventListener("wallet-standard:register-wallet", handleRegisterWalletEvent);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Could not add register-wallet event listener", { error });
|
|
263
|
+
}
|
|
264
|
+
class AppReadyEvent extends Event {
|
|
265
|
+
constructor(api) {
|
|
266
|
+
super("wallet-standard:app-ready", {
|
|
267
|
+
bubbles: false,
|
|
268
|
+
cancelable: false,
|
|
269
|
+
composed: false
|
|
270
|
+
});
|
|
271
|
+
this.detail = api;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
window.dispatchEvent(new AppReadyEvent(registerAPI));
|
|
276
|
+
debug.log(DebugCategory.BROWSER_SDK, "Dispatched wallet-standard:app-ready event");
|
|
277
|
+
} catch (error) {
|
|
278
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Could not dispatch app-ready event", { error });
|
|
279
|
+
}
|
|
280
|
+
const walletsAPI = {
|
|
281
|
+
getWallets: () => {
|
|
282
|
+
return {
|
|
283
|
+
get: getRegisteredWallets,
|
|
284
|
+
on: (_event, _listener) => {
|
|
285
|
+
return () => {
|
|
286
|
+
};
|
|
287
|
+
},
|
|
288
|
+
register
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
if (!navigator.wallets) {
|
|
293
|
+
navigator.wallets = walletsAPI;
|
|
294
|
+
}
|
|
295
|
+
debug.log(DebugCategory.BROWSER_SDK, "Initialized Wallet Standard registry");
|
|
296
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
297
|
+
const existingWalletsAPI = navigator.wallets || window.wallets;
|
|
298
|
+
if (!existingWalletsAPI || typeof existingWalletsAPI.getWallets !== "function") {
|
|
299
|
+
const logData = {
|
|
300
|
+
hasNavigator: !!navigator,
|
|
301
|
+
hasWindow: typeof window !== "undefined",
|
|
302
|
+
note: "Wallet Standard API not properly initialized"
|
|
303
|
+
};
|
|
304
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard API not available", logData);
|
|
305
|
+
return wallets;
|
|
306
|
+
}
|
|
307
|
+
const walletsGetter = existingWalletsAPI.getWallets();
|
|
308
|
+
const getWalletsFn = () => Promise.resolve([...walletsGetter.get()]);
|
|
309
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard API detected, starting discovery");
|
|
310
|
+
try {
|
|
311
|
+
let registeredWallets = [];
|
|
312
|
+
let attempts = 0;
|
|
313
|
+
const maxAttempts = 5;
|
|
314
|
+
const initialDelay = 100;
|
|
315
|
+
const eip6963Timeout = 400;
|
|
316
|
+
await new Promise((resolve) => setTimeout(resolve, initialDelay));
|
|
317
|
+
while (attempts < maxAttempts) {
|
|
318
|
+
registeredWallets = await getWalletsFn();
|
|
319
|
+
const logData = {
|
|
320
|
+
attempt: attempts + 1,
|
|
321
|
+
walletCount: registeredWallets.length,
|
|
322
|
+
walletNames: registeredWallets.map((w) => w.name),
|
|
323
|
+
chains: registeredWallets.flatMap((w) => w.chains)
|
|
324
|
+
};
|
|
325
|
+
debug.log(DebugCategory.BROWSER_SDK, `Wallet Standard getWallets attempt ${attempts + 1}`, logData);
|
|
326
|
+
if (registeredWallets.length > 0 || attempts === maxAttempts - 1) {
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
await new Promise((resolve) => setTimeout(resolve, initialDelay));
|
|
330
|
+
attempts++;
|
|
331
|
+
}
|
|
332
|
+
const totalWaitTime = initialDelay + attempts * initialDelay;
|
|
333
|
+
if (totalWaitTime < eip6963Timeout) {
|
|
334
|
+
const remainingWait = eip6963Timeout - totalWaitTime;
|
|
335
|
+
await new Promise((resolve) => setTimeout(resolve, remainingWait));
|
|
336
|
+
registeredWallets = await getWalletsFn();
|
|
337
|
+
}
|
|
338
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard getWallets final result", {
|
|
339
|
+
walletCount: registeredWallets.length,
|
|
340
|
+
walletNames: registeredWallets.map((w) => w.name),
|
|
341
|
+
attempts: attempts + 1
|
|
342
|
+
});
|
|
343
|
+
for (const wallet of registeredWallets) {
|
|
344
|
+
const supportsSolana = wallet.chains.some((chain) => {
|
|
345
|
+
const chainLower = chain.toLowerCase();
|
|
346
|
+
return chainLower.startsWith("solana:") || chainLower === "solana";
|
|
347
|
+
}) || wallet.features && typeof wallet.features === "object" && Object.keys(wallet.features).some((featureKey) => {
|
|
348
|
+
const featureLower = featureKey.toLowerCase();
|
|
349
|
+
return featureLower.includes("solana") || featureLower.includes("standard:connect") || featureLower.includes("standard:signTransaction");
|
|
350
|
+
});
|
|
351
|
+
if (!supportsSolana) {
|
|
352
|
+
const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
|
|
353
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet does not support Solana", {
|
|
354
|
+
walletName: wallet.name,
|
|
355
|
+
chains: wallet.chains,
|
|
356
|
+
featureKeys
|
|
357
|
+
});
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (wallet.name.toLowerCase().includes("phantom")) {
|
|
361
|
+
debug.log(DebugCategory.BROWSER_SDK, "Skipping Phantom from Wallet Standard (handled separately)");
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
const walletId = generateWalletIdFromName(wallet.name);
|
|
365
|
+
const safeFeatures = wallet.features ? Object.keys(wallet.features) : [];
|
|
366
|
+
debug.log(DebugCategory.BROWSER_SDK, "Discovered Wallet Standard Solana wallet", {
|
|
367
|
+
walletId,
|
|
368
|
+
walletName: wallet.name,
|
|
369
|
+
chains: wallet.chains,
|
|
370
|
+
featureKeys: safeFeatures,
|
|
371
|
+
icon: wallet.icon,
|
|
372
|
+
version: wallet.version,
|
|
373
|
+
accountCount: wallet.accounts?.length || 0
|
|
374
|
+
});
|
|
375
|
+
wallets.push({
|
|
376
|
+
id: walletId,
|
|
377
|
+
name: wallet.name,
|
|
378
|
+
icon: wallet.icon,
|
|
379
|
+
addressTypes: [import_client2.AddressType.solana],
|
|
380
|
+
providers: {
|
|
381
|
+
// Cast to ISolanaChain - Wallet Standard wallets have compatible methods
|
|
382
|
+
// The InjectedWalletSolanaChain wrapper will handle the actual method calls
|
|
383
|
+
solana: wallet
|
|
384
|
+
},
|
|
385
|
+
discovery: "standard"
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
} catch (error) {
|
|
389
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Wallet Standard API error", {
|
|
390
|
+
error: error instanceof Error ? error.message : String(error),
|
|
391
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
const finalLogData = {
|
|
395
|
+
discoveredCount: wallets.length,
|
|
396
|
+
walletIds: wallets.map((w) => w.id),
|
|
397
|
+
walletNames: wallets.map((w) => w.name)
|
|
398
|
+
};
|
|
399
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard Solana discovery completed", finalLogData);
|
|
400
|
+
return wallets;
|
|
401
|
+
}
|
|
402
|
+
function discoverPhantomWallet(addressTypes) {
|
|
403
|
+
if (typeof window === "undefined") {
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
if (!(0, import_browser_injected_sdk.isPhantomExtensionInstalled)()) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
const plugins = [(0, import_browser_injected_sdk2.createExtensionPlugin)()];
|
|
410
|
+
if (addressTypes.includes(import_client2.AddressType.solana)) {
|
|
411
|
+
plugins.push((0, import_solana.createSolanaPlugin)());
|
|
412
|
+
}
|
|
413
|
+
if (addressTypes.includes(import_client2.AddressType.ethereum)) {
|
|
414
|
+
plugins.push((0, import_ethereum.createEthereumPlugin)());
|
|
415
|
+
}
|
|
416
|
+
plugins.push((0, import_auto_confirm.createAutoConfirmPlugin)());
|
|
417
|
+
const phantomInstance = (0, import_browser_injected_sdk2.createPhantom)({ plugins });
|
|
418
|
+
return {
|
|
419
|
+
id: "phantom",
|
|
420
|
+
name: "Phantom",
|
|
421
|
+
icon: void 0,
|
|
422
|
+
// Icon will be rendered from icons package in UI components
|
|
423
|
+
addressTypes,
|
|
424
|
+
providers: {
|
|
425
|
+
solana: addressTypes.includes(import_client2.AddressType.solana) ? phantomInstance.solana : void 0,
|
|
426
|
+
ethereum: addressTypes.includes(import_client2.AddressType.ethereum) ? phantomInstance.ethereum : void 0
|
|
427
|
+
},
|
|
428
|
+
isPhantom: true,
|
|
429
|
+
phantomInstance,
|
|
430
|
+
discovery: "phantom"
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
async function discoverWallets(addressTypes) {
|
|
434
|
+
const requestedAddressTypes = addressTypes || [];
|
|
435
|
+
debug.log(DebugCategory.BROWSER_SDK, "Starting all wallet discovery methods", {
|
|
436
|
+
addressTypes: requestedAddressTypes
|
|
437
|
+
});
|
|
438
|
+
const [solanaWallets, ethereumWallets] = await Promise.all([discoverSolanaWallets(), discoverEthereumWallets()]);
|
|
439
|
+
const phantomWallet = discoverPhantomWallet(requestedAddressTypes);
|
|
440
|
+
debug.log(DebugCategory.BROWSER_SDK, "All wallet discovery methods completed", {
|
|
441
|
+
phantomFound: !!phantomWallet,
|
|
442
|
+
solanaWalletsCount: solanaWallets.length,
|
|
443
|
+
ethereumWalletsCount: ethereumWallets.length,
|
|
444
|
+
solanaWalletIds: solanaWallets.map((w) => w.id),
|
|
445
|
+
ethereumWalletIds: ethereumWallets.map((w) => w.id)
|
|
446
|
+
});
|
|
447
|
+
const walletMap = /* @__PURE__ */ new Map();
|
|
448
|
+
if (phantomWallet) {
|
|
449
|
+
walletMap.set("phantom", phantomWallet);
|
|
450
|
+
}
|
|
451
|
+
for (const wallet of [...solanaWallets, ...ethereumWallets]) {
|
|
452
|
+
const existing = walletMap.get(wallet.id);
|
|
453
|
+
if (existing) {
|
|
454
|
+
const mergedAddressTypes = Array.from(/* @__PURE__ */ new Set([...existing.addressTypes, ...wallet.addressTypes]));
|
|
455
|
+
const mergedProviders = {
|
|
456
|
+
...existing.providers,
|
|
457
|
+
...wallet.providers
|
|
458
|
+
};
|
|
459
|
+
const mergedWallet = {
|
|
460
|
+
...existing,
|
|
461
|
+
addressTypes: mergedAddressTypes,
|
|
462
|
+
// Prefer icon from the most recent discovery
|
|
463
|
+
icon: wallet.icon || existing.icon,
|
|
464
|
+
providers: mergedProviders
|
|
465
|
+
};
|
|
466
|
+
walletMap.set(wallet.id, mergedWallet);
|
|
467
|
+
debug.log(DebugCategory.BROWSER_SDK, "Merged wallet by ID", {
|
|
468
|
+
walletName: wallet.name,
|
|
469
|
+
walletId: wallet.id,
|
|
470
|
+
existingAddressTypes: existing.addressTypes,
|
|
471
|
+
newAddressTypes: wallet.addressTypes,
|
|
472
|
+
mergedAddressTypes,
|
|
473
|
+
existingProviders: Object.keys(existing.providers || {}),
|
|
474
|
+
newProviders: Object.keys(wallet.providers || {}),
|
|
475
|
+
mergedProviders: Object.keys(mergedProviders)
|
|
476
|
+
});
|
|
477
|
+
debug.log(DebugCategory.BROWSER_SDK, "Merged wallet from multiple discovery methods", {
|
|
478
|
+
walletId: wallet.id,
|
|
479
|
+
walletName: wallet.name,
|
|
480
|
+
existingAddressTypes: existing.addressTypes,
|
|
481
|
+
newAddressTypes: wallet.addressTypes,
|
|
482
|
+
mergedAddressTypes
|
|
483
|
+
});
|
|
484
|
+
} else {
|
|
485
|
+
walletMap.set(wallet.id, wallet);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return Array.from(walletMap.values());
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// src/providers/injected/chains/InjectedWalletSolanaChain.ts
|
|
492
|
+
var import_eventemitter3 = require("eventemitter3");
|
|
126
493
|
var import_buffer = require("buffer");
|
|
127
|
-
var
|
|
128
|
-
constructor(
|
|
494
|
+
var InjectedWalletSolanaChain = class {
|
|
495
|
+
constructor(provider, walletId, walletName) {
|
|
496
|
+
this.eventEmitter = new import_eventemitter3.EventEmitter();
|
|
129
497
|
this._connected = false;
|
|
130
498
|
this._publicKey = null;
|
|
131
|
-
this.
|
|
132
|
-
this.
|
|
133
|
-
this.
|
|
499
|
+
this.provider = provider;
|
|
500
|
+
this.walletId = walletId;
|
|
501
|
+
this.walletName = walletName;
|
|
134
502
|
this.setupEventListeners();
|
|
135
|
-
this.syncInitialState();
|
|
136
503
|
}
|
|
137
|
-
// Wallet adapter compliant properties
|
|
138
504
|
get connected() {
|
|
139
505
|
return this._connected;
|
|
140
506
|
}
|
|
141
507
|
get publicKey() {
|
|
142
508
|
return this._publicKey;
|
|
143
509
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
510
|
+
async connect(options) {
|
|
511
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect", {
|
|
512
|
+
walletId: this.walletId,
|
|
513
|
+
walletName: this.walletName,
|
|
514
|
+
onlyIfTrusted: options?.onlyIfTrusted
|
|
515
|
+
});
|
|
516
|
+
try {
|
|
517
|
+
const result = await this.provider.connect(options);
|
|
518
|
+
if (typeof result === "string") {
|
|
519
|
+
this._connected = true;
|
|
520
|
+
this._publicKey = result;
|
|
521
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
|
|
522
|
+
walletId: this.walletId,
|
|
523
|
+
walletName: this.walletName,
|
|
524
|
+
publicKey: result
|
|
525
|
+
});
|
|
526
|
+
return { publicKey: result };
|
|
527
|
+
}
|
|
528
|
+
if (typeof result === "object" && result !== null && "publicKey" in result) {
|
|
529
|
+
this._connected = true;
|
|
530
|
+
this._publicKey = result.publicKey;
|
|
531
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
|
|
532
|
+
walletId: this.walletId,
|
|
533
|
+
walletName: this.walletName,
|
|
534
|
+
publicKey: result.publicKey
|
|
535
|
+
});
|
|
536
|
+
return result;
|
|
537
|
+
}
|
|
538
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
539
|
+
const firstAccount = result[0];
|
|
540
|
+
if (typeof firstAccount === "object" && firstAccount !== null && "address" in firstAccount) {
|
|
541
|
+
this._connected = true;
|
|
542
|
+
this._publicKey = firstAccount.address;
|
|
543
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
|
|
544
|
+
walletId: this.walletId,
|
|
545
|
+
walletName: this.walletName,
|
|
546
|
+
publicKey: firstAccount.address
|
|
547
|
+
});
|
|
548
|
+
return { publicKey: firstAccount.address };
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
throw new Error("Unexpected connect result format");
|
|
552
|
+
} catch (error) {
|
|
553
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect failed", {
|
|
554
|
+
walletId: this.walletId,
|
|
555
|
+
walletName: this.walletName,
|
|
556
|
+
error: error instanceof Error ? error.message : String(error)
|
|
557
|
+
});
|
|
558
|
+
throw error;
|
|
153
559
|
}
|
|
154
|
-
this.updateConnectionState(true, solanaAddress.address);
|
|
155
|
-
return Promise.resolve({ publicKey: solanaAddress.address });
|
|
156
560
|
}
|
|
157
561
|
async disconnect() {
|
|
158
|
-
|
|
562
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnect", {
|
|
563
|
+
walletId: this.walletId,
|
|
564
|
+
walletName: this.walletName
|
|
565
|
+
});
|
|
566
|
+
try {
|
|
567
|
+
await this.provider.disconnect();
|
|
568
|
+
this._connected = false;
|
|
569
|
+
this._publicKey = null;
|
|
570
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnected", {
|
|
571
|
+
walletId: this.walletId,
|
|
572
|
+
walletName: this.walletName
|
|
573
|
+
});
|
|
574
|
+
} catch (error) {
|
|
575
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnect failed", {
|
|
576
|
+
walletId: this.walletId,
|
|
577
|
+
walletName: this.walletName,
|
|
578
|
+
error: error instanceof Error ? error.message : String(error)
|
|
579
|
+
});
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
159
582
|
}
|
|
160
|
-
// Standard wallet adapter methods
|
|
161
583
|
async signMessage(message) {
|
|
162
584
|
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
585
|
+
const messagePreview = typeof message === "string" ? message.substring(0, 50) : `${messageBytes.length} bytes`;
|
|
586
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signMessage", {
|
|
587
|
+
walletId: this.walletId,
|
|
588
|
+
walletName: this.walletName,
|
|
589
|
+
messagePreview,
|
|
590
|
+
messageLength: messageBytes.length
|
|
591
|
+
});
|
|
592
|
+
try {
|
|
593
|
+
const result = await this.provider.signMessage(message);
|
|
594
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signMessage success", {
|
|
595
|
+
walletId: this.walletId,
|
|
596
|
+
walletName: this.walletName,
|
|
597
|
+
signatureLength: result.signature.length
|
|
598
|
+
});
|
|
599
|
+
return {
|
|
600
|
+
signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(import_buffer.Buffer.from(result.signature, "base64")),
|
|
601
|
+
publicKey: result.publicKey || this._publicKey || ""
|
|
602
|
+
};
|
|
603
|
+
} catch (error) {
|
|
604
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signMessage failed", {
|
|
605
|
+
walletId: this.walletId,
|
|
606
|
+
walletName: this.walletName,
|
|
607
|
+
error: error instanceof Error ? error.message : String(error)
|
|
608
|
+
});
|
|
609
|
+
throw error;
|
|
610
|
+
}
|
|
168
611
|
}
|
|
169
612
|
async signTransaction(transaction) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
613
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signTransaction", {
|
|
614
|
+
walletId: this.walletId,
|
|
615
|
+
walletName: this.walletName
|
|
616
|
+
});
|
|
173
617
|
try {
|
|
174
|
-
const result = await this.
|
|
618
|
+
const result = await this.provider.signTransaction(transaction);
|
|
619
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signTransaction success", {
|
|
620
|
+
walletId: this.walletId,
|
|
621
|
+
walletName: this.walletName
|
|
622
|
+
});
|
|
175
623
|
return result;
|
|
176
624
|
} catch (error) {
|
|
177
|
-
|
|
625
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signTransaction failed", {
|
|
626
|
+
walletId: this.walletId,
|
|
627
|
+
walletName: this.walletName,
|
|
628
|
+
error: error instanceof Error ? error.message : String(error)
|
|
629
|
+
});
|
|
630
|
+
throw error;
|
|
178
631
|
}
|
|
179
632
|
}
|
|
180
633
|
async signAndSendTransaction(transaction) {
|
|
181
|
-
|
|
182
|
-
|
|
634
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendTransaction", {
|
|
635
|
+
walletId: this.walletId,
|
|
636
|
+
walletName: this.walletName
|
|
637
|
+
});
|
|
638
|
+
try {
|
|
639
|
+
const result = await this.provider.signAndSendTransaction(transaction);
|
|
640
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendTransaction success", {
|
|
641
|
+
walletId: this.walletId,
|
|
642
|
+
walletName: this.walletName,
|
|
643
|
+
signature: result.signature
|
|
644
|
+
});
|
|
645
|
+
return result;
|
|
646
|
+
} catch (error) {
|
|
647
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendTransaction failed", {
|
|
648
|
+
walletId: this.walletId,
|
|
649
|
+
walletName: this.walletName,
|
|
650
|
+
error: error instanceof Error ? error.message : String(error)
|
|
651
|
+
});
|
|
652
|
+
throw error;
|
|
653
|
+
}
|
|
183
654
|
}
|
|
184
655
|
async signAllTransactions(transactions) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
656
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAllTransactions", {
|
|
657
|
+
walletId: this.walletId,
|
|
658
|
+
walletName: this.walletName,
|
|
659
|
+
transactionCount: transactions.length
|
|
660
|
+
});
|
|
188
661
|
try {
|
|
189
|
-
const result = await this.
|
|
662
|
+
const result = await this.provider.signAllTransactions(transactions);
|
|
663
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAllTransactions success", {
|
|
664
|
+
walletId: this.walletId,
|
|
665
|
+
walletName: this.walletName,
|
|
666
|
+
signedCount: result.length
|
|
667
|
+
});
|
|
190
668
|
return result;
|
|
191
669
|
} catch (error) {
|
|
192
|
-
|
|
670
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAllTransactions failed", {
|
|
671
|
+
walletId: this.walletId,
|
|
672
|
+
walletName: this.walletName,
|
|
673
|
+
error: error instanceof Error ? error.message : String(error)
|
|
674
|
+
});
|
|
675
|
+
throw error;
|
|
193
676
|
}
|
|
194
677
|
}
|
|
195
678
|
async signAndSendAllTransactions(transactions) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
679
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendAllTransactions", {
|
|
680
|
+
walletId: this.walletId,
|
|
681
|
+
walletName: this.walletName,
|
|
682
|
+
transactionCount: transactions.length
|
|
683
|
+
});
|
|
199
684
|
try {
|
|
200
|
-
const result = await this.
|
|
201
|
-
|
|
685
|
+
const result = await this.provider.signAndSendAllTransactions(transactions);
|
|
686
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendAllTransactions success", {
|
|
687
|
+
walletId: this.walletId,
|
|
688
|
+
walletName: this.walletName,
|
|
689
|
+
signatureCount: result.signatures.length
|
|
690
|
+
});
|
|
691
|
+
return result;
|
|
202
692
|
} catch (error) {
|
|
203
|
-
|
|
693
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendAllTransactions failed", {
|
|
694
|
+
walletId: this.walletId,
|
|
695
|
+
walletName: this.walletName,
|
|
696
|
+
error: error instanceof Error ? error.message : String(error)
|
|
697
|
+
});
|
|
698
|
+
throw error;
|
|
204
699
|
}
|
|
205
700
|
}
|
|
206
701
|
switchNetwork(_network) {
|
|
207
702
|
return Promise.resolve();
|
|
208
703
|
}
|
|
209
|
-
// Legacy methods
|
|
210
704
|
getPublicKey() {
|
|
211
705
|
return Promise.resolve(this._publicKey);
|
|
212
706
|
}
|
|
213
707
|
isConnected() {
|
|
214
|
-
return this._connected
|
|
708
|
+
return this._connected;
|
|
215
709
|
}
|
|
216
710
|
setupEventListeners() {
|
|
217
|
-
this.
|
|
218
|
-
this.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
this.updateConnectionState(true, solanaAddress.address);
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
this.callbacks.on("disconnect", () => {
|
|
236
|
-
this.updateConnectionState(false, null);
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
syncInitialState() {
|
|
240
|
-
if (this.callbacks.isConnected()) {
|
|
241
|
-
const solanaAddress = this.callbacks.getAddresses().find((addr) => addr.addressType === import_client2.AddressType.solana);
|
|
242
|
-
if (solanaAddress) {
|
|
243
|
-
this.updateConnectionState(true, solanaAddress.address);
|
|
244
|
-
}
|
|
711
|
+
if (typeof this.provider.on === "function") {
|
|
712
|
+
this.provider.on("connect", (publicKey) => {
|
|
713
|
+
this._connected = true;
|
|
714
|
+
this._publicKey = publicKey;
|
|
715
|
+
this.eventEmitter.emit("connect", publicKey);
|
|
716
|
+
});
|
|
717
|
+
this.provider.on("disconnect", () => {
|
|
718
|
+
this._connected = false;
|
|
719
|
+
this._publicKey = null;
|
|
720
|
+
this.eventEmitter.emit("disconnect");
|
|
721
|
+
});
|
|
722
|
+
this.provider.on("accountChanged", (publicKey) => {
|
|
723
|
+
this._publicKey = publicKey;
|
|
724
|
+
this.eventEmitter.emit("accountChanged", publicKey);
|
|
725
|
+
});
|
|
245
726
|
}
|
|
246
727
|
}
|
|
247
|
-
updateConnectionState(connected, publicKey) {
|
|
248
|
-
this._connected = connected;
|
|
249
|
-
this._publicKey = publicKey;
|
|
250
|
-
}
|
|
251
|
-
// Event methods for interface compliance
|
|
252
728
|
on(event, listener) {
|
|
253
729
|
this.eventEmitter.on(event, listener);
|
|
254
730
|
}
|
|
@@ -257,52 +733,851 @@ var InjectedSolanaChain = class {
|
|
|
257
733
|
}
|
|
258
734
|
};
|
|
259
735
|
|
|
260
|
-
// src/providers/injected/chains/
|
|
261
|
-
var
|
|
262
|
-
var
|
|
263
|
-
var
|
|
264
|
-
constructor(
|
|
736
|
+
// src/providers/injected/chains/WalletStandardSolanaAdapter.ts
|
|
737
|
+
var import_parsers = require("@phantom/parsers");
|
|
738
|
+
var import_bs58 = __toESM(require("bs58"));
|
|
739
|
+
var WalletStandardSolanaAdapter = class {
|
|
740
|
+
constructor(wallet, walletId, walletName) {
|
|
265
741
|
this._connected = false;
|
|
266
|
-
this.
|
|
267
|
-
this.
|
|
268
|
-
this.
|
|
269
|
-
this.
|
|
270
|
-
this.callbacks = callbacks;
|
|
271
|
-
this.setupEventListeners();
|
|
272
|
-
this.syncInitialState();
|
|
742
|
+
this._publicKey = null;
|
|
743
|
+
this.wallet = wallet;
|
|
744
|
+
this.walletId = walletId;
|
|
745
|
+
this.walletName = walletName;
|
|
273
746
|
}
|
|
274
|
-
// EIP-1193 compliant properties
|
|
275
747
|
get connected() {
|
|
276
748
|
return this._connected;
|
|
277
749
|
}
|
|
278
|
-
get
|
|
279
|
-
return this.
|
|
280
|
-
}
|
|
281
|
-
get accounts() {
|
|
282
|
-
return this._accounts;
|
|
750
|
+
get publicKey() {
|
|
751
|
+
return this._publicKey;
|
|
283
752
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
753
|
+
async connect(_options) {
|
|
754
|
+
try {
|
|
755
|
+
const connectFeature = this.wallet.features?.["standard:connect"];
|
|
756
|
+
if (!connectFeature || typeof connectFeature.connect !== "function") {
|
|
757
|
+
throw new Error("Wallet Standard connect feature not available");
|
|
758
|
+
}
|
|
759
|
+
const connectResult = await connectFeature.connect();
|
|
760
|
+
let accounts;
|
|
761
|
+
if (Array.isArray(connectResult) && connectResult.length > 0) {
|
|
762
|
+
accounts = connectResult;
|
|
763
|
+
} else if (this.wallet.accounts && this.wallet.accounts.length > 0) {
|
|
764
|
+
accounts = Array.from(this.wallet.accounts);
|
|
765
|
+
}
|
|
766
|
+
if (!accounts || accounts.length === 0) {
|
|
767
|
+
throw new Error("No accounts available after connecting to wallet");
|
|
768
|
+
}
|
|
769
|
+
const firstAccount = accounts[0];
|
|
770
|
+
if (!firstAccount) {
|
|
771
|
+
throw new Error("First account is null or undefined");
|
|
772
|
+
}
|
|
773
|
+
let address;
|
|
774
|
+
if (typeof firstAccount === "string") {
|
|
775
|
+
address = firstAccount;
|
|
776
|
+
} else if (typeof firstAccount === "object" && firstAccount !== null) {
|
|
777
|
+
address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? Buffer.from(firstAccount.publicKey).toString("hex") : void 0);
|
|
778
|
+
}
|
|
779
|
+
if (!address) {
|
|
780
|
+
throw new Error(
|
|
781
|
+
`Could not extract address from account. Account structure: ${JSON.stringify(firstAccount, null, 2)}`
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
this._connected = true;
|
|
785
|
+
this._publicKey = address;
|
|
786
|
+
return { publicKey: address };
|
|
787
|
+
} catch (error) {
|
|
788
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana connect failed", {
|
|
789
|
+
walletId: this.walletId,
|
|
790
|
+
walletName: this.walletName,
|
|
791
|
+
error: error instanceof Error ? error.message : String(error)
|
|
792
|
+
});
|
|
793
|
+
throw error;
|
|
290
794
|
}
|
|
291
|
-
const provider = await this.phantom.ethereum.getProvider();
|
|
292
|
-
return await provider.request(args);
|
|
293
795
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
796
|
+
async disconnect() {
|
|
797
|
+
try {
|
|
798
|
+
const disconnectFeature = this.wallet.features?.["standard:disconnect"];
|
|
799
|
+
if (disconnectFeature && typeof disconnectFeature.disconnect === "function") {
|
|
800
|
+
await disconnectFeature.disconnect();
|
|
801
|
+
}
|
|
802
|
+
this._connected = false;
|
|
803
|
+
this._publicKey = null;
|
|
804
|
+
} catch (error) {
|
|
805
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana disconnect failed", {
|
|
806
|
+
walletId: this.walletId,
|
|
807
|
+
walletName: this.walletName,
|
|
808
|
+
error: error instanceof Error ? error.message : String(error)
|
|
809
|
+
});
|
|
810
|
+
throw error;
|
|
298
811
|
}
|
|
299
|
-
const addresses = this.callbacks.getAddresses();
|
|
300
|
-
const ethAddresses = addresses.filter((addr) => addr.addressType === import_client3.AddressType.ethereum).map((addr) => addr.address);
|
|
301
|
-
this.updateConnectionState(true, ethAddresses);
|
|
302
|
-
return Promise.resolve(ethAddresses);
|
|
303
812
|
}
|
|
304
|
-
async
|
|
305
|
-
|
|
813
|
+
async signMessage(message) {
|
|
814
|
+
try {
|
|
815
|
+
const signMessageFeature = this.wallet.features?.["solana:signMessage"];
|
|
816
|
+
if (!signMessageFeature || typeof signMessageFeature.signMessage !== "function") {
|
|
817
|
+
throw new Error("Wallet Standard signMessage feature not available");
|
|
818
|
+
}
|
|
819
|
+
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
820
|
+
const result = await signMessageFeature.signMessage({
|
|
821
|
+
message: messageBytes,
|
|
822
|
+
account: this.wallet.accounts?.[0]
|
|
823
|
+
});
|
|
824
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
825
|
+
throw new Error(`Expected array result from signMessage, got: ${typeof result}`);
|
|
826
|
+
}
|
|
827
|
+
const signedMessageResult = result[0];
|
|
828
|
+
if (!signedMessageResult || !signedMessageResult.signature) {
|
|
829
|
+
throw new Error(`Invalid signMessage result structure: ${JSON.stringify(result)}`);
|
|
830
|
+
}
|
|
831
|
+
const signature = this.parseUint8Array(signedMessageResult.signature);
|
|
832
|
+
if (signature.length === 0) {
|
|
833
|
+
throw new Error(`Signature is empty`);
|
|
834
|
+
}
|
|
835
|
+
const publicKey = signedMessageResult.account?.address || this.wallet.accounts?.[0]?.address || this._publicKey || "";
|
|
836
|
+
return { signature, publicKey };
|
|
837
|
+
} catch (error) {
|
|
838
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signMessage failed", {
|
|
839
|
+
walletId: this.walletId,
|
|
840
|
+
walletName: this.walletName,
|
|
841
|
+
error: error instanceof Error ? error.message : String(error)
|
|
842
|
+
});
|
|
843
|
+
throw error;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
async signTransaction(transaction) {
|
|
847
|
+
try {
|
|
848
|
+
const signTransactionFeature = this.wallet.features?.["solana:signTransaction"];
|
|
849
|
+
if (!signTransactionFeature || typeof signTransactionFeature.signTransaction !== "function") {
|
|
850
|
+
throw new Error("Wallet Standard signTransaction feature not available");
|
|
851
|
+
}
|
|
852
|
+
if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
|
|
853
|
+
throw new Error("No accounts available. Please connect first.");
|
|
854
|
+
}
|
|
855
|
+
const account = this.wallet.accounts[0];
|
|
856
|
+
const serializedTransaction = this.serializeTransaction(transaction);
|
|
857
|
+
const results = await signTransactionFeature.signTransaction({
|
|
858
|
+
transaction: serializedTransaction,
|
|
859
|
+
account
|
|
860
|
+
});
|
|
861
|
+
let transactionData;
|
|
862
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
863
|
+
const firstItem = results[0];
|
|
864
|
+
if (firstItem && typeof firstItem === "object") {
|
|
865
|
+
transactionData = firstItem.signedTransaction || firstItem.transaction;
|
|
866
|
+
}
|
|
867
|
+
} else if (results && typeof results === "object" && !Array.isArray(results)) {
|
|
868
|
+
transactionData = results.transaction || results.signedTransaction;
|
|
869
|
+
}
|
|
870
|
+
if (!transactionData) {
|
|
871
|
+
throw new Error("No transaction data found in Wallet Standard result");
|
|
872
|
+
}
|
|
873
|
+
const signedBytes = this.parseUint8Array(transactionData);
|
|
874
|
+
if (signedBytes.length === 0) {
|
|
875
|
+
throw new Error("Empty signed transaction returned from Wallet Standard");
|
|
876
|
+
}
|
|
877
|
+
const signedTx = (0, import_parsers.deserializeSolanaTransaction)(signedBytes);
|
|
878
|
+
return signedTx;
|
|
879
|
+
} catch (error) {
|
|
880
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signTransaction failed", {
|
|
881
|
+
walletId: this.walletId,
|
|
882
|
+
walletName: this.walletName,
|
|
883
|
+
error: error instanceof Error ? error.message : String(error)
|
|
884
|
+
});
|
|
885
|
+
throw error;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
async signAndSendTransaction(transaction) {
|
|
889
|
+
try {
|
|
890
|
+
const signAndSendTransactionFeature = this.wallet.features?.["solana:signAndSendTransaction"];
|
|
891
|
+
if (!signAndSendTransactionFeature || typeof signAndSendTransactionFeature.signAndSendTransaction !== "function") {
|
|
892
|
+
throw new Error("Wallet Standard signAndSendTransaction feature not available");
|
|
893
|
+
}
|
|
894
|
+
if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
|
|
895
|
+
throw new Error("No accounts available. Please connect first.");
|
|
896
|
+
}
|
|
897
|
+
const account = this.wallet.accounts[0];
|
|
898
|
+
const chain = account.chains?.[0] || "solana:mainnet";
|
|
899
|
+
const serializedTransaction = this.serializeTransaction(transaction);
|
|
900
|
+
const results = await signAndSendTransactionFeature.signAndSendTransaction({
|
|
901
|
+
transaction: serializedTransaction,
|
|
902
|
+
account,
|
|
903
|
+
chain
|
|
904
|
+
});
|
|
905
|
+
let signatureOutput;
|
|
906
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
907
|
+
signatureOutput = results[0];
|
|
908
|
+
} else if (results && typeof results === "object" && !Array.isArray(results)) {
|
|
909
|
+
signatureOutput = results;
|
|
910
|
+
} else {
|
|
911
|
+
throw new Error("Invalid signAndSendTransaction result format");
|
|
912
|
+
}
|
|
913
|
+
if (!signatureOutput.signature) {
|
|
914
|
+
throw new Error("No signature found in signAndSendTransaction result");
|
|
915
|
+
}
|
|
916
|
+
const signatureBytes = this.parseUint8Array(signatureOutput.signature);
|
|
917
|
+
const signature = import_bs58.default.encode(signatureBytes);
|
|
918
|
+
return { signature };
|
|
919
|
+
} catch (error) {
|
|
920
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signAndSendTransaction failed", {
|
|
921
|
+
walletId: this.walletId,
|
|
922
|
+
walletName: this.walletName,
|
|
923
|
+
error: error instanceof Error ? error.message : String(error)
|
|
924
|
+
});
|
|
925
|
+
throw error;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
async signAllTransactions(transactions) {
|
|
929
|
+
try {
|
|
930
|
+
const signedTransactions = [];
|
|
931
|
+
for (const transaction of transactions) {
|
|
932
|
+
const signedTx = await this.signTransaction(transaction);
|
|
933
|
+
signedTransactions.push(signedTx);
|
|
934
|
+
}
|
|
935
|
+
return signedTransactions;
|
|
936
|
+
} catch (error) {
|
|
937
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signAllTransactions failed", {
|
|
938
|
+
walletId: this.walletId,
|
|
939
|
+
walletName: this.walletName,
|
|
940
|
+
error: error instanceof Error ? error.message : String(error)
|
|
941
|
+
});
|
|
942
|
+
throw error;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
async signAndSendAllTransactions(transactions) {
|
|
946
|
+
try {
|
|
947
|
+
const signatures = [];
|
|
948
|
+
for (const transaction of transactions) {
|
|
949
|
+
const result = await this.signAndSendTransaction(transaction);
|
|
950
|
+
signatures.push(result.signature);
|
|
951
|
+
}
|
|
952
|
+
return { signatures };
|
|
953
|
+
} catch (error) {
|
|
954
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signAndSendAllTransactions failed", {
|
|
955
|
+
walletId: this.walletId,
|
|
956
|
+
walletName: this.walletName,
|
|
957
|
+
error: error instanceof Error ? error.message : String(error)
|
|
958
|
+
});
|
|
959
|
+
throw error;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
async switchNetwork(network) {
|
|
963
|
+
try {
|
|
964
|
+
const switchNetworkFeature = this.wallet.features?.["standard:switchNetwork"];
|
|
965
|
+
if (switchNetworkFeature && typeof switchNetworkFeature.switchNetwork === "function") {
|
|
966
|
+
const chainId = network === "mainnet" ? "solana:mainnet" : "solana:devnet";
|
|
967
|
+
await switchNetworkFeature.switchNetwork({ chain: chainId });
|
|
968
|
+
}
|
|
969
|
+
} catch (error) {
|
|
970
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana switchNetwork failed", {
|
|
971
|
+
walletId: this.walletId,
|
|
972
|
+
walletName: this.walletName,
|
|
973
|
+
network,
|
|
974
|
+
error: error instanceof Error ? error.message : String(error)
|
|
975
|
+
});
|
|
976
|
+
throw error;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
getPublicKey() {
|
|
980
|
+
return Promise.resolve(this._publicKey);
|
|
981
|
+
}
|
|
982
|
+
isConnected() {
|
|
983
|
+
return this._connected;
|
|
984
|
+
}
|
|
985
|
+
on(_event, _listener) {
|
|
986
|
+
const eventsFeature = this.wallet.features?.["standard:events"];
|
|
987
|
+
if (eventsFeature && typeof eventsFeature.on === "function") {
|
|
988
|
+
eventsFeature.on(_event, _listener);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
off(_event, _listener) {
|
|
992
|
+
const eventsFeature = this.wallet.features?.["standard:events"];
|
|
993
|
+
if (eventsFeature && typeof eventsFeature.off === "function") {
|
|
994
|
+
eventsFeature.off(_event, _listener);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Serialize a transaction to Uint8Array for Wallet Standard API
|
|
999
|
+
*/
|
|
1000
|
+
serializeTransaction(transaction) {
|
|
1001
|
+
if (typeof transaction.serialize === "function") {
|
|
1002
|
+
return transaction.serialize({
|
|
1003
|
+
requireAllSignatures: false,
|
|
1004
|
+
verifySignatures: false
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
if (transaction instanceof Uint8Array) {
|
|
1008
|
+
return transaction;
|
|
1009
|
+
}
|
|
1010
|
+
return new Uint8Array(0);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Parse a Uint8Array from various formats
|
|
1014
|
+
* Handles: Uint8Array, Array, object with numeric keys (JSON-serialized Uint8Array)
|
|
1015
|
+
*/
|
|
1016
|
+
parseUint8Array(value) {
|
|
1017
|
+
if (value instanceof Uint8Array) {
|
|
1018
|
+
return value;
|
|
1019
|
+
}
|
|
1020
|
+
if (Array.isArray(value)) {
|
|
1021
|
+
return new Uint8Array(value);
|
|
1022
|
+
}
|
|
1023
|
+
if (typeof value === "object" && value !== null) {
|
|
1024
|
+
const keys = Object.keys(value).map(Number).filter((k) => !isNaN(k) && k >= 0).sort((a, b) => a - b);
|
|
1025
|
+
if (keys.length > 0) {
|
|
1026
|
+
const maxKey = Math.max(...keys);
|
|
1027
|
+
const array = new Uint8Array(maxKey + 1);
|
|
1028
|
+
for (const key of keys) {
|
|
1029
|
+
array[key] = Number(value[key]) || 0;
|
|
1030
|
+
}
|
|
1031
|
+
return array;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return new Uint8Array(0);
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
// src/providers/injected/chains/InjectedWalletEthereumChain.ts
|
|
1039
|
+
var import_eventemitter32 = require("eventemitter3");
|
|
1040
|
+
var InjectedWalletEthereumChain = class {
|
|
1041
|
+
constructor(provider, walletId, walletName) {
|
|
1042
|
+
this.eventEmitter = new import_eventemitter32.EventEmitter();
|
|
1043
|
+
this._connected = false;
|
|
1044
|
+
this._chainId = "0x1";
|
|
1045
|
+
this._accounts = [];
|
|
1046
|
+
this.provider = provider;
|
|
1047
|
+
this.walletId = walletId;
|
|
1048
|
+
this.walletName = walletName;
|
|
1049
|
+
this.setupEventListeners();
|
|
1050
|
+
}
|
|
1051
|
+
get connected() {
|
|
1052
|
+
return this._connected;
|
|
1053
|
+
}
|
|
1054
|
+
get chainId() {
|
|
1055
|
+
return this._chainId;
|
|
1056
|
+
}
|
|
1057
|
+
get accounts() {
|
|
1058
|
+
return this._accounts;
|
|
1059
|
+
}
|
|
1060
|
+
async request(args) {
|
|
1061
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request", {
|
|
1062
|
+
walletId: this.walletId,
|
|
1063
|
+
walletName: this.walletName,
|
|
1064
|
+
method: args.method
|
|
1065
|
+
});
|
|
1066
|
+
try {
|
|
1067
|
+
const requiresAuth = [
|
|
1068
|
+
"personal_sign",
|
|
1069
|
+
"eth_sign",
|
|
1070
|
+
"eth_signTypedData",
|
|
1071
|
+
"eth_signTypedData_v4",
|
|
1072
|
+
"eth_sendTransaction",
|
|
1073
|
+
"eth_signTransaction"
|
|
1074
|
+
].includes(args.method);
|
|
1075
|
+
if (requiresAuth && (!this._connected || this._accounts.length === 0)) {
|
|
1076
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Method requires authorization, ensuring connection", {
|
|
1077
|
+
walletId: this.walletId,
|
|
1078
|
+
walletName: this.walletName,
|
|
1079
|
+
method: args.method
|
|
1080
|
+
});
|
|
1081
|
+
await this.connect();
|
|
1082
|
+
}
|
|
1083
|
+
const result = await this.provider.request(args);
|
|
1084
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request success", {
|
|
1085
|
+
walletId: this.walletId,
|
|
1086
|
+
walletName: this.walletName,
|
|
1087
|
+
method: args.method
|
|
1088
|
+
});
|
|
1089
|
+
return result;
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
if (error?.code === 4100) {
|
|
1092
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Got 4100 Unauthorized, attempting to re-authorize", {
|
|
1093
|
+
walletId: this.walletId,
|
|
1094
|
+
walletName: this.walletName,
|
|
1095
|
+
method: args.method
|
|
1096
|
+
});
|
|
1097
|
+
try {
|
|
1098
|
+
await this.provider.request({ method: "eth_requestAccounts" });
|
|
1099
|
+
const result = await this.provider.request(args);
|
|
1100
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request success (after re-auth)", {
|
|
1101
|
+
walletId: this.walletId,
|
|
1102
|
+
walletName: this.walletName,
|
|
1103
|
+
method: args.method
|
|
1104
|
+
});
|
|
1105
|
+
return result;
|
|
1106
|
+
} catch (retryError) {
|
|
1107
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Failed after re-authorization", {
|
|
1108
|
+
walletId: this.walletId,
|
|
1109
|
+
walletName: this.walletName,
|
|
1110
|
+
method: args.method,
|
|
1111
|
+
error: retryError instanceof Error ? retryError.message : String(retryError)
|
|
1112
|
+
});
|
|
1113
|
+
throw retryError;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request failed", {
|
|
1117
|
+
walletId: this.walletId,
|
|
1118
|
+
walletName: this.walletName,
|
|
1119
|
+
method: args.method,
|
|
1120
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1121
|
+
errorCode: error?.code
|
|
1122
|
+
});
|
|
1123
|
+
throw error;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
async connect() {
|
|
1127
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum connect", {
|
|
1128
|
+
walletId: this.walletId,
|
|
1129
|
+
walletName: this.walletName
|
|
1130
|
+
});
|
|
1131
|
+
try {
|
|
1132
|
+
const accounts = await this.provider.request({ method: "eth_requestAccounts" });
|
|
1133
|
+
this._connected = accounts.length > 0;
|
|
1134
|
+
this._accounts = accounts;
|
|
1135
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum connected (via eth_requestAccounts)", {
|
|
1136
|
+
walletId: this.walletId,
|
|
1137
|
+
walletName: this.walletName,
|
|
1138
|
+
accountCount: accounts.length,
|
|
1139
|
+
accounts
|
|
1140
|
+
});
|
|
1141
|
+
return accounts;
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum connect failed", {
|
|
1144
|
+
walletId: this.walletId,
|
|
1145
|
+
walletName: this.walletName,
|
|
1146
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1147
|
+
});
|
|
1148
|
+
throw error;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
async disconnect() {
|
|
1152
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum disconnect", {
|
|
1153
|
+
walletId: this.walletId,
|
|
1154
|
+
walletName: this.walletName
|
|
1155
|
+
});
|
|
1156
|
+
try {
|
|
1157
|
+
await this.provider.disconnect();
|
|
1158
|
+
this._connected = false;
|
|
1159
|
+
this._accounts = [];
|
|
1160
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum disconnected", {
|
|
1161
|
+
walletId: this.walletId,
|
|
1162
|
+
walletName: this.walletName
|
|
1163
|
+
});
|
|
1164
|
+
} catch (error) {
|
|
1165
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum disconnect failed", {
|
|
1166
|
+
walletId: this.walletId,
|
|
1167
|
+
walletName: this.walletName,
|
|
1168
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1169
|
+
});
|
|
1170
|
+
throw error;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
async signPersonalMessage(message, address) {
|
|
1174
|
+
const messagePreview = message.length > 50 ? message.substring(0, 50) + "..." : message;
|
|
1175
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage", {
|
|
1176
|
+
walletId: this.walletId,
|
|
1177
|
+
walletName: this.walletName,
|
|
1178
|
+
messagePreview,
|
|
1179
|
+
messageLength: message.length,
|
|
1180
|
+
address
|
|
1181
|
+
});
|
|
1182
|
+
try {
|
|
1183
|
+
const providerConnected = this.provider.isConnected?.() || this.provider.connected || false;
|
|
1184
|
+
if (!this._connected || this._accounts.length === 0 || !providerConnected) {
|
|
1185
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Not connected, attempting to connect before signing", {
|
|
1186
|
+
walletId: this.walletId,
|
|
1187
|
+
walletName: this.walletName,
|
|
1188
|
+
internalConnected: this._connected,
|
|
1189
|
+
accountsLength: this._accounts.length,
|
|
1190
|
+
providerConnected
|
|
1191
|
+
});
|
|
1192
|
+
await this.connect();
|
|
1193
|
+
}
|
|
1194
|
+
const normalizedAddress = address.toLowerCase();
|
|
1195
|
+
const normalizedAccounts = this._accounts.map((acc) => acc.toLowerCase());
|
|
1196
|
+
if (!normalizedAccounts.includes(normalizedAddress)) {
|
|
1197
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Address not in connected accounts, refreshing connection", {
|
|
1198
|
+
walletId: this.walletId,
|
|
1199
|
+
walletName: this.walletName,
|
|
1200
|
+
requestedAddress: address,
|
|
1201
|
+
connectedAccounts: this._accounts
|
|
1202
|
+
});
|
|
1203
|
+
const currentAccounts = await this.getAccounts();
|
|
1204
|
+
const normalizedCurrentAccounts = currentAccounts.map((acc) => acc.toLowerCase());
|
|
1205
|
+
if (!normalizedCurrentAccounts.includes(normalizedAddress)) {
|
|
1206
|
+
throw new Error(`Address ${address} is not connected. Connected accounts: ${currentAccounts.join(", ")}`);
|
|
1207
|
+
}
|
|
1208
|
+
this._accounts = currentAccounts;
|
|
1209
|
+
}
|
|
1210
|
+
if (typeof this.provider.signPersonalMessage === "function") {
|
|
1211
|
+
const result2 = await this.provider.signPersonalMessage(message, address);
|
|
1212
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage success", {
|
|
1213
|
+
walletId: this.walletId,
|
|
1214
|
+
walletName: this.walletName,
|
|
1215
|
+
signatureLength: result2.length
|
|
1216
|
+
});
|
|
1217
|
+
return result2;
|
|
1218
|
+
}
|
|
1219
|
+
const result = await this.request({
|
|
1220
|
+
method: "personal_sign",
|
|
1221
|
+
params: [message, address]
|
|
1222
|
+
});
|
|
1223
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage success", {
|
|
1224
|
+
walletId: this.walletId,
|
|
1225
|
+
walletName: this.walletName,
|
|
1226
|
+
signatureLength: result.length
|
|
1227
|
+
});
|
|
1228
|
+
return result;
|
|
1229
|
+
} catch (error) {
|
|
1230
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage failed", {
|
|
1231
|
+
walletId: this.walletId,
|
|
1232
|
+
walletName: this.walletName,
|
|
1233
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1234
|
+
errorCode: error?.code
|
|
1235
|
+
});
|
|
1236
|
+
throw error;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
async signTypedData(typedData, address) {
|
|
1240
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData", {
|
|
1241
|
+
walletId: this.walletId,
|
|
1242
|
+
walletName: this.walletName,
|
|
1243
|
+
primaryType: typedData?.primaryType,
|
|
1244
|
+
address
|
|
1245
|
+
});
|
|
1246
|
+
try {
|
|
1247
|
+
if (typeof this.provider.signTypedData === "function") {
|
|
1248
|
+
const result2 = await this.provider.signTypedData(typedData, address);
|
|
1249
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData success", {
|
|
1250
|
+
walletId: this.walletId,
|
|
1251
|
+
walletName: this.walletName,
|
|
1252
|
+
signatureLength: result2.length
|
|
1253
|
+
});
|
|
1254
|
+
return result2;
|
|
1255
|
+
}
|
|
1256
|
+
const result = await this.request({
|
|
1257
|
+
method: "eth_signTypedData_v4",
|
|
1258
|
+
params: [address, typedData]
|
|
1259
|
+
});
|
|
1260
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData success", {
|
|
1261
|
+
walletId: this.walletId,
|
|
1262
|
+
walletName: this.walletName,
|
|
1263
|
+
signatureLength: result.length
|
|
1264
|
+
});
|
|
1265
|
+
return result;
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData failed", {
|
|
1268
|
+
walletId: this.walletId,
|
|
1269
|
+
walletName: this.walletName,
|
|
1270
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1271
|
+
});
|
|
1272
|
+
throw error;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
async signTransaction(transaction) {
|
|
1276
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction", {
|
|
1277
|
+
walletId: this.walletId,
|
|
1278
|
+
walletName: this.walletName,
|
|
1279
|
+
from: transaction.from,
|
|
1280
|
+
to: transaction.to
|
|
1281
|
+
});
|
|
1282
|
+
try {
|
|
1283
|
+
if (typeof this.provider.signTransaction === "function") {
|
|
1284
|
+
const result2 = await this.provider.signTransaction(transaction);
|
|
1285
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction success", {
|
|
1286
|
+
walletId: this.walletId,
|
|
1287
|
+
walletName: this.walletName,
|
|
1288
|
+
signatureLength: result2.length
|
|
1289
|
+
});
|
|
1290
|
+
return result2;
|
|
1291
|
+
}
|
|
1292
|
+
const result = await this.request({
|
|
1293
|
+
method: "eth_signTransaction",
|
|
1294
|
+
params: [transaction]
|
|
1295
|
+
});
|
|
1296
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction success", {
|
|
1297
|
+
walletId: this.walletId,
|
|
1298
|
+
walletName: this.walletName,
|
|
1299
|
+
signatureLength: result.length
|
|
1300
|
+
});
|
|
1301
|
+
return result;
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction failed", {
|
|
1304
|
+
walletId: this.walletId,
|
|
1305
|
+
walletName: this.walletName,
|
|
1306
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1307
|
+
});
|
|
1308
|
+
throw error;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
async sendTransaction(transaction) {
|
|
1312
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction", {
|
|
1313
|
+
walletId: this.walletId,
|
|
1314
|
+
walletName: this.walletName,
|
|
1315
|
+
from: transaction.from,
|
|
1316
|
+
to: transaction.to,
|
|
1317
|
+
value: transaction.value
|
|
1318
|
+
});
|
|
1319
|
+
try {
|
|
1320
|
+
if (typeof this.provider.sendTransaction === "function") {
|
|
1321
|
+
const result2 = await this.provider.sendTransaction(transaction);
|
|
1322
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction success", {
|
|
1323
|
+
walletId: this.walletId,
|
|
1324
|
+
walletName: this.walletName,
|
|
1325
|
+
txHash: result2
|
|
1326
|
+
});
|
|
1327
|
+
return result2;
|
|
1328
|
+
}
|
|
1329
|
+
const result = await this.request({
|
|
1330
|
+
method: "eth_sendTransaction",
|
|
1331
|
+
params: [transaction]
|
|
1332
|
+
});
|
|
1333
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction success", {
|
|
1334
|
+
walletId: this.walletId,
|
|
1335
|
+
walletName: this.walletName,
|
|
1336
|
+
txHash: result
|
|
1337
|
+
});
|
|
1338
|
+
return result;
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction failed", {
|
|
1341
|
+
walletId: this.walletId,
|
|
1342
|
+
walletName: this.walletName,
|
|
1343
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1344
|
+
});
|
|
1345
|
+
throw error;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
async switchChain(chainId) {
|
|
1349
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum switchChain", {
|
|
1350
|
+
walletId: this.walletId,
|
|
1351
|
+
walletName: this.walletName,
|
|
1352
|
+
chainId
|
|
1353
|
+
});
|
|
1354
|
+
try {
|
|
1355
|
+
const hexChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? chainId : `0x${parseInt(chainId, 10).toString(16)}` : `0x${chainId.toString(16)}`;
|
|
1356
|
+
if (typeof this.provider.switchChain === "function") {
|
|
1357
|
+
await this.provider.switchChain(hexChainId);
|
|
1358
|
+
} else {
|
|
1359
|
+
await this.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hexChainId }] });
|
|
1360
|
+
}
|
|
1361
|
+
this._chainId = hexChainId;
|
|
1362
|
+
this.eventEmitter.emit("chainChanged", this._chainId);
|
|
1363
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum switchChain success", {
|
|
1364
|
+
walletId: this.walletId,
|
|
1365
|
+
walletName: this.walletName,
|
|
1366
|
+
chainId: hexChainId
|
|
1367
|
+
});
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum switchChain failed", {
|
|
1370
|
+
walletId: this.walletId,
|
|
1371
|
+
walletName: this.walletName,
|
|
1372
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1373
|
+
});
|
|
1374
|
+
throw error;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
async getChainId() {
|
|
1378
|
+
if (typeof this.provider.getChainId === "function") {
|
|
1379
|
+
const chainId2 = await this.provider.getChainId();
|
|
1380
|
+
this._chainId = `0x${chainId2.toString(16)}`;
|
|
1381
|
+
return chainId2;
|
|
1382
|
+
}
|
|
1383
|
+
const chainId = await this.request({ method: "eth_chainId" });
|
|
1384
|
+
const parsed = parseInt(chainId, 16);
|
|
1385
|
+
this._chainId = chainId;
|
|
1386
|
+
return parsed;
|
|
1387
|
+
}
|
|
1388
|
+
async getAccounts() {
|
|
1389
|
+
if (typeof this.provider.getAccounts === "function") {
|
|
1390
|
+
const accounts2 = await this.provider.getAccounts();
|
|
1391
|
+
this._accounts = accounts2;
|
|
1392
|
+
return accounts2;
|
|
1393
|
+
}
|
|
1394
|
+
const accounts = await this.request({ method: "eth_accounts" });
|
|
1395
|
+
this._accounts = accounts;
|
|
1396
|
+
return accounts;
|
|
1397
|
+
}
|
|
1398
|
+
isConnected() {
|
|
1399
|
+
return this._connected;
|
|
1400
|
+
}
|
|
1401
|
+
setupEventListeners() {
|
|
1402
|
+
if (typeof this.provider.on === "function") {
|
|
1403
|
+
this.provider.on("connect", (info) => {
|
|
1404
|
+
this._connected = true;
|
|
1405
|
+
this._chainId = info.chainId;
|
|
1406
|
+
this.eventEmitter.emit("connect", info);
|
|
1407
|
+
});
|
|
1408
|
+
this.provider.on("disconnect", (error) => {
|
|
1409
|
+
this._connected = false;
|
|
1410
|
+
this._accounts = [];
|
|
1411
|
+
this.eventEmitter.emit("disconnect", error);
|
|
1412
|
+
this.eventEmitter.emit("accountsChanged", []);
|
|
1413
|
+
});
|
|
1414
|
+
this.provider.on("accountsChanged", (accounts) => {
|
|
1415
|
+
this._accounts = accounts;
|
|
1416
|
+
this.eventEmitter.emit("accountsChanged", accounts);
|
|
1417
|
+
});
|
|
1418
|
+
this.provider.on("chainChanged", (chainId) => {
|
|
1419
|
+
this._chainId = chainId;
|
|
1420
|
+
this.eventEmitter.emit("chainChanged", chainId);
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
on(event, listener) {
|
|
1425
|
+
this.eventEmitter.on(event, listener);
|
|
1426
|
+
}
|
|
1427
|
+
off(event, listener) {
|
|
1428
|
+
this.eventEmitter.off(event, listener);
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1432
|
+
// src/providers/injected/chains/SolanaChain.ts
|
|
1433
|
+
var import_eventemitter33 = require("eventemitter3");
|
|
1434
|
+
var import_buffer2 = require("buffer");
|
|
1435
|
+
var PhantomSolanaChain = class {
|
|
1436
|
+
constructor(phantom) {
|
|
1437
|
+
this._publicKey = null;
|
|
1438
|
+
this.eventEmitter = new import_eventemitter33.EventEmitter();
|
|
1439
|
+
this.phantom = phantom;
|
|
1440
|
+
this.setupEventListeners();
|
|
1441
|
+
}
|
|
1442
|
+
// Wallet adapter compliant properties
|
|
1443
|
+
get connected() {
|
|
1444
|
+
return this._publicKey !== null;
|
|
1445
|
+
}
|
|
1446
|
+
get publicKey() {
|
|
1447
|
+
return this._publicKey;
|
|
1448
|
+
}
|
|
1449
|
+
// Connection methods
|
|
1450
|
+
async connect(options) {
|
|
1451
|
+
const result = await this.phantom.solana.connect(options);
|
|
1452
|
+
if (!result) {
|
|
1453
|
+
throw new Error("Failed to connect to Solana wallet");
|
|
1454
|
+
}
|
|
1455
|
+
const publicKey = typeof result === "string" ? result : "";
|
|
1456
|
+
this._publicKey = publicKey;
|
|
1457
|
+
return { publicKey };
|
|
1458
|
+
}
|
|
1459
|
+
async disconnect() {
|
|
1460
|
+
await this.phantom.solana.disconnect();
|
|
1461
|
+
this._publicKey = null;
|
|
1462
|
+
}
|
|
1463
|
+
// Standard wallet adapter methods
|
|
1464
|
+
async signMessage(message) {
|
|
1465
|
+
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
1466
|
+
const result = await this.phantom.solana.signMessage(messageBytes);
|
|
1467
|
+
return {
|
|
1468
|
+
signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(import_buffer2.Buffer.from(result.signature, "base64")),
|
|
1469
|
+
publicKey: this._publicKey || ""
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
async signTransaction(transaction) {
|
|
1473
|
+
if (!this.connected) {
|
|
1474
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
1475
|
+
}
|
|
1476
|
+
try {
|
|
1477
|
+
const result = await this.phantom.solana.signTransaction(transaction);
|
|
1478
|
+
return result;
|
|
1479
|
+
} catch (error) {
|
|
1480
|
+
return Promise.reject(error);
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
async signAndSendTransaction(transaction) {
|
|
1484
|
+
const result = await this.phantom.solana.signAndSendTransaction(transaction);
|
|
1485
|
+
return { signature: result.signature };
|
|
1486
|
+
}
|
|
1487
|
+
async signAllTransactions(transactions) {
|
|
1488
|
+
if (!this.connected) {
|
|
1489
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
1490
|
+
}
|
|
1491
|
+
try {
|
|
1492
|
+
const result = await this.phantom.solana.signAllTransactions(transactions);
|
|
1493
|
+
return result;
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
return Promise.reject(error);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
async signAndSendAllTransactions(transactions) {
|
|
1499
|
+
if (!this.connected) {
|
|
1500
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
1501
|
+
}
|
|
1502
|
+
try {
|
|
1503
|
+
const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
|
|
1504
|
+
return { signatures: result.signatures };
|
|
1505
|
+
} catch (error) {
|
|
1506
|
+
return Promise.reject(error);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
switchNetwork(_network) {
|
|
1510
|
+
return Promise.resolve();
|
|
1511
|
+
}
|
|
1512
|
+
// Legacy methods
|
|
1513
|
+
getPublicKey() {
|
|
1514
|
+
return Promise.resolve(this._publicKey);
|
|
1515
|
+
}
|
|
1516
|
+
isConnected() {
|
|
1517
|
+
return this.connected;
|
|
1518
|
+
}
|
|
1519
|
+
setupEventListeners() {
|
|
1520
|
+
this.phantom.solana.addEventListener("connect", (publicKey) => {
|
|
1521
|
+
this._publicKey = publicKey;
|
|
1522
|
+
this.eventEmitter.emit("connect", publicKey);
|
|
1523
|
+
});
|
|
1524
|
+
this.phantom.solana.addEventListener("disconnect", () => {
|
|
1525
|
+
this._publicKey = null;
|
|
1526
|
+
this.eventEmitter.emit("disconnect");
|
|
1527
|
+
});
|
|
1528
|
+
this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
|
|
1529
|
+
this._publicKey = publicKey;
|
|
1530
|
+
this.eventEmitter.emit("accountChanged", publicKey);
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
// Event methods for interface compliance
|
|
1534
|
+
on(event, listener) {
|
|
1535
|
+
this.eventEmitter.on(event, listener);
|
|
1536
|
+
}
|
|
1537
|
+
off(event, listener) {
|
|
1538
|
+
this.eventEmitter.off(event, listener);
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
// src/providers/injected/chains/EthereumChain.ts
|
|
1543
|
+
var import_eventemitter34 = require("eventemitter3");
|
|
1544
|
+
var PhantomEthereumChain = class {
|
|
1545
|
+
constructor(phantom) {
|
|
1546
|
+
this._chainId = "0x1";
|
|
1547
|
+
this._accounts = [];
|
|
1548
|
+
this.eventEmitter = new import_eventemitter34.EventEmitter();
|
|
1549
|
+
this.phantom = phantom;
|
|
1550
|
+
this.setupEventListeners();
|
|
1551
|
+
}
|
|
1552
|
+
// EIP-1193 compliant properties
|
|
1553
|
+
get connected() {
|
|
1554
|
+
return this._accounts.length > 0;
|
|
1555
|
+
}
|
|
1556
|
+
get chainId() {
|
|
1557
|
+
return this._chainId;
|
|
1558
|
+
}
|
|
1559
|
+
get accounts() {
|
|
1560
|
+
return this._accounts;
|
|
1561
|
+
}
|
|
1562
|
+
// EIP-1193 core method with eth_signTransaction support
|
|
1563
|
+
async request(args) {
|
|
1564
|
+
if (args.method === "eth_signTransaction") {
|
|
1565
|
+
const [transaction] = args.params;
|
|
1566
|
+
const result = await this.signTransaction(transaction);
|
|
1567
|
+
return result;
|
|
1568
|
+
}
|
|
1569
|
+
const phantomProvider = await this.phantom.ethereum.getProvider();
|
|
1570
|
+
return await phantomProvider.request(args);
|
|
1571
|
+
}
|
|
1572
|
+
// Connection methods
|
|
1573
|
+
async connect() {
|
|
1574
|
+
const accounts = await this.phantom.ethereum.getAccounts();
|
|
1575
|
+
this._accounts = accounts;
|
|
1576
|
+
return accounts;
|
|
1577
|
+
}
|
|
1578
|
+
async disconnect() {
|
|
1579
|
+
await this.phantom.ethereum.disconnect();
|
|
1580
|
+
this._accounts = [];
|
|
306
1581
|
}
|
|
307
1582
|
// Standard compliant methods (return raw values, not wrapped objects)
|
|
308
1583
|
async signPersonalMessage(message, address) {
|
|
@@ -318,8 +1593,9 @@ var InjectedEthereumChain = class {
|
|
|
318
1593
|
return await this.phantom.ethereum.sendTransaction(transaction);
|
|
319
1594
|
}
|
|
320
1595
|
async switchChain(chainId) {
|
|
321
|
-
|
|
322
|
-
this.
|
|
1596
|
+
const hexChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? chainId : `0x${parseInt(chainId, 10).toString(16)}` : `0x${chainId.toString(16)}`;
|
|
1597
|
+
await this.phantom.ethereum.switchChain(hexChainId);
|
|
1598
|
+
this._chainId = hexChainId;
|
|
323
1599
|
this.eventEmitter.emit("chainChanged", this._chainId);
|
|
324
1600
|
}
|
|
325
1601
|
async getChainId() {
|
|
@@ -330,16 +1606,16 @@ var InjectedEthereumChain = class {
|
|
|
330
1606
|
return await this.phantom.ethereum.getAccounts();
|
|
331
1607
|
}
|
|
332
1608
|
isConnected() {
|
|
333
|
-
return this.
|
|
1609
|
+
return this.connected;
|
|
334
1610
|
}
|
|
335
1611
|
setupEventListeners() {
|
|
336
1612
|
this.phantom.ethereum.addEventListener("connect", (accounts) => {
|
|
337
|
-
this.
|
|
1613
|
+
this._accounts = accounts;
|
|
338
1614
|
this.eventEmitter.emit("connect", { chainId: this._chainId });
|
|
339
1615
|
this.eventEmitter.emit("accountsChanged", accounts);
|
|
340
1616
|
});
|
|
341
1617
|
this.phantom.ethereum.addEventListener("disconnect", () => {
|
|
342
|
-
this.
|
|
1618
|
+
this._accounts = [];
|
|
343
1619
|
this.eventEmitter.emit("disconnect", { code: 4900, message: "Provider disconnected" });
|
|
344
1620
|
this.eventEmitter.emit("accountsChanged", []);
|
|
345
1621
|
});
|
|
@@ -351,254 +1627,532 @@ var InjectedEthereumChain = class {
|
|
|
351
1627
|
this._chainId = chainId;
|
|
352
1628
|
this.eventEmitter.emit("chainChanged", chainId);
|
|
353
1629
|
});
|
|
354
|
-
this.callbacks.on("connect", (data) => {
|
|
355
|
-
const ethAddresses = data.addresses?.filter((addr) => addr.addressType === import_client3.AddressType.ethereum)?.map((addr) => addr.address) || [];
|
|
356
|
-
if (ethAddresses.length > 0) {
|
|
357
|
-
this.updateConnectionState(true, ethAddresses);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
this.callbacks.on("disconnect", () => {
|
|
361
|
-
this.updateConnectionState(false, []);
|
|
362
|
-
});
|
|
363
1630
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
1631
|
+
// Event methods for interface compliance
|
|
1632
|
+
on(event, listener) {
|
|
1633
|
+
this.eventEmitter.on(event, listener);
|
|
1634
|
+
}
|
|
1635
|
+
off(event, listener) {
|
|
1636
|
+
this.eventEmitter.off(event, listener);
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
|
|
1640
|
+
// src/wallets/registry.ts
|
|
1641
|
+
function isPhantomWallet(wallet) {
|
|
1642
|
+
return wallet !== void 0 && wallet.id === "phantom" && "isPhantom" in wallet && wallet.isPhantom === true;
|
|
1643
|
+
}
|
|
1644
|
+
var InjectedWalletRegistry = class {
|
|
1645
|
+
constructor() {
|
|
1646
|
+
this.wallets = /* @__PURE__ */ new Map();
|
|
1647
|
+
this.discoveryPromise = null;
|
|
1648
|
+
}
|
|
1649
|
+
register(info) {
|
|
1650
|
+
const wrappedProviders = {};
|
|
1651
|
+
if (info.providers?.solana) {
|
|
1652
|
+
const isWalletStandard = info.providers.solana && typeof info.providers.solana === "object" && "features" in info.providers.solana && typeof info.providers.solana.features === "object";
|
|
1653
|
+
if (isWalletStandard) {
|
|
1654
|
+
wrappedProviders.solana = new WalletStandardSolanaAdapter(info.providers.solana, info.id, info.name);
|
|
1655
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wrapped Wallet Standard Solana wallet with adapter", {
|
|
1656
|
+
walletId: info.id,
|
|
1657
|
+
walletName: info.name
|
|
1658
|
+
});
|
|
1659
|
+
} else {
|
|
1660
|
+
wrappedProviders.solana = new InjectedWalletSolanaChain(info.providers.solana, info.id, info.name);
|
|
1661
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wrapped Solana provider with InjectedWalletSolanaChain", {
|
|
1662
|
+
walletId: info.id,
|
|
1663
|
+
walletName: info.name
|
|
1664
|
+
});
|
|
369
1665
|
}
|
|
370
1666
|
}
|
|
1667
|
+
if (info.providers?.ethereum) {
|
|
1668
|
+
wrappedProviders.ethereum = new InjectedWalletEthereumChain(info.providers.ethereum, info.id, info.name);
|
|
1669
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wrapped Ethereum provider with InjectedWalletEthereumChain", {
|
|
1670
|
+
walletId: info.id,
|
|
1671
|
+
walletName: info.name
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
const wrappedInfo = {
|
|
1675
|
+
...info,
|
|
1676
|
+
providers: Object.keys(wrappedProviders).length > 0 ? wrappedProviders : info.providers
|
|
1677
|
+
};
|
|
1678
|
+
this.wallets.set(info.id, wrappedInfo);
|
|
1679
|
+
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Register Phantom wallet with its instance
|
|
1682
|
+
* This creates wrapped providers and stores the Phantom instance for auto-confirm access
|
|
1683
|
+
*/
|
|
1684
|
+
registerPhantom(phantomInstance, addressTypes) {
|
|
1685
|
+
const wrappedProviders = {};
|
|
1686
|
+
if (addressTypes.includes(import_client.AddressType.solana) && phantomInstance.solana) {
|
|
1687
|
+
wrappedProviders.solana = new PhantomSolanaChain(phantomInstance);
|
|
1688
|
+
debug.log(DebugCategory.BROWSER_SDK, "Created PhantomSolanaChain wrapper", {
|
|
1689
|
+
walletId: "phantom"
|
|
1690
|
+
});
|
|
1691
|
+
}
|
|
1692
|
+
if (addressTypes.includes(import_client.AddressType.ethereum) && phantomInstance.ethereum) {
|
|
1693
|
+
wrappedProviders.ethereum = new PhantomEthereumChain(phantomInstance);
|
|
1694
|
+
debug.log(DebugCategory.BROWSER_SDK, "Created PhantomEthereumChain wrapper", {
|
|
1695
|
+
walletId: "phantom"
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
const phantomWallet = {
|
|
1699
|
+
id: "phantom",
|
|
1700
|
+
name: "Phantom",
|
|
1701
|
+
icon: "",
|
|
1702
|
+
// Icon will be rendered from icons package in UI components
|
|
1703
|
+
addressTypes,
|
|
1704
|
+
providers: wrappedProviders,
|
|
1705
|
+
isPhantom: true,
|
|
1706
|
+
phantomInstance,
|
|
1707
|
+
discovery: "phantom"
|
|
1708
|
+
};
|
|
1709
|
+
this.wallets.set("phantom", phantomWallet);
|
|
1710
|
+
debug.log(DebugCategory.BROWSER_SDK, "Registered Phantom wallet with chain wrappers", {
|
|
1711
|
+
addressTypes,
|
|
1712
|
+
hasSolana: !!wrappedProviders.solana,
|
|
1713
|
+
hasEthereum: !!wrappedProviders.ethereum
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
unregister(id) {
|
|
1717
|
+
this.wallets.delete(id);
|
|
1718
|
+
}
|
|
1719
|
+
has(id) {
|
|
1720
|
+
return this.wallets.has(id);
|
|
1721
|
+
}
|
|
1722
|
+
getById(id) {
|
|
1723
|
+
return this.wallets.get(id);
|
|
371
1724
|
}
|
|
372
|
-
|
|
373
|
-
this.
|
|
374
|
-
this._accounts = accounts;
|
|
1725
|
+
getAll() {
|
|
1726
|
+
return Array.from(this.wallets.values());
|
|
375
1727
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
1728
|
+
getByAddressTypes(addressTypes) {
|
|
1729
|
+
if (addressTypes.length === 0) {
|
|
1730
|
+
return this.getAll();
|
|
1731
|
+
}
|
|
1732
|
+
const allowed = new Set(addressTypes);
|
|
1733
|
+
return this.getAll().filter((wallet) => wallet.addressTypes.some((t) => allowed.has(t)));
|
|
379
1734
|
}
|
|
380
|
-
|
|
381
|
-
this.
|
|
1735
|
+
discover(addressTypes) {
|
|
1736
|
+
if (this.discoveryPromise) {
|
|
1737
|
+
return this.discoveryPromise;
|
|
1738
|
+
}
|
|
1739
|
+
debug.log(DebugCategory.BROWSER_SDK, "Starting wallet discovery", { addressTypes });
|
|
1740
|
+
this.discoveryPromise = discoverWallets(addressTypes).then((discoveredWallets) => {
|
|
1741
|
+
const relevantWallets = addressTypes ? discoveredWallets.filter((wallet) => wallet.addressTypes.some((type) => addressTypes.includes(type))) : discoveredWallets;
|
|
1742
|
+
for (const wallet of relevantWallets) {
|
|
1743
|
+
if (wallet.id === "phantom" && isPhantomWallet(wallet)) {
|
|
1744
|
+
this.registerPhantom(wallet.phantomInstance, wallet.addressTypes);
|
|
1745
|
+
} else {
|
|
1746
|
+
this.register(wallet);
|
|
1747
|
+
}
|
|
1748
|
+
debug.log(DebugCategory.BROWSER_SDK, "Registered discovered wallet", {
|
|
1749
|
+
id: wallet.id,
|
|
1750
|
+
name: wallet.name,
|
|
1751
|
+
addressTypes: wallet.addressTypes
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
debug.info(DebugCategory.BROWSER_SDK, "Wallet discovery completed", {
|
|
1755
|
+
totalDiscovered: discoveredWallets.length,
|
|
1756
|
+
relevantWallets: relevantWallets.length
|
|
1757
|
+
});
|
|
1758
|
+
}).catch((error) => {
|
|
1759
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Wallet discovery failed", { error });
|
|
1760
|
+
this.discoveryPromise = null;
|
|
1761
|
+
throw error;
|
|
1762
|
+
});
|
|
1763
|
+
return this.discoveryPromise;
|
|
382
1764
|
}
|
|
383
1765
|
};
|
|
1766
|
+
var walletRegistry = null;
|
|
1767
|
+
function getWalletRegistry() {
|
|
1768
|
+
if (!walletRegistry) {
|
|
1769
|
+
walletRegistry = new InjectedWalletRegistry();
|
|
1770
|
+
}
|
|
1771
|
+
return walletRegistry;
|
|
1772
|
+
}
|
|
384
1773
|
|
|
385
1774
|
// src/providers/injected/index.ts
|
|
1775
|
+
var WAS_CONNECTED_KEY = "phantom-injected-was-connected";
|
|
1776
|
+
var WAS_CONNECTED_VALUE = "true";
|
|
1777
|
+
var LAST_WALLET_ID_KEY = "phantom-injected-last-wallet-id";
|
|
386
1778
|
var InjectedProvider = class {
|
|
1779
|
+
// Track which wallets have event listeners set up
|
|
387
1780
|
constructor(config) {
|
|
388
|
-
this.
|
|
389
|
-
this.
|
|
1781
|
+
this.selectedWalletId = null;
|
|
1782
|
+
this.walletStates = /* @__PURE__ */ new Map();
|
|
390
1783
|
// Event management
|
|
391
1784
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
392
1785
|
this.browserInjectedCleanupFunctions = [];
|
|
393
1786
|
this.eventsInitialized = false;
|
|
1787
|
+
this.externalWalletEventListenersSetup = /* @__PURE__ */ new Set();
|
|
394
1788
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
|
|
395
1789
|
this.addressTypes = config.addressTypes;
|
|
1790
|
+
this.walletRegistry = getWalletRegistry();
|
|
396
1791
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
plugins.push((0, import_solana.createSolanaPlugin)());
|
|
400
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana plugin added");
|
|
401
|
-
}
|
|
402
|
-
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
403
|
-
plugins.push((0, import_ethereum.createEthereumPlugin)());
|
|
404
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum plugin added");
|
|
405
|
-
}
|
|
406
|
-
plugins.push((0, import_auto_confirm.createAutoConfirmPlugin)());
|
|
407
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "AutoConfirm plugin added");
|
|
408
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Creating Phantom instance with plugins", {
|
|
409
|
-
pluginCount: plugins.length
|
|
1792
|
+
this.walletRegistry.discover(this.addressTypes).catch((error) => {
|
|
1793
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Wallet discovery failed during initialization", { error });
|
|
410
1794
|
});
|
|
411
|
-
this.phantom = (0, import_browser_injected_sdk.createPhantom)({ plugins });
|
|
412
|
-
const callbacks = this.createCallbacks();
|
|
413
|
-
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
414
|
-
this._solanaChain = new InjectedSolanaChain(this.phantom, callbacks);
|
|
415
|
-
}
|
|
416
|
-
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
417
|
-
this._ethereumChain = new InjectedEthereumChain(this.phantom, callbacks);
|
|
418
|
-
}
|
|
419
1795
|
debug.info(DebugCategory.INJECTED_PROVIDER, "InjectedProvider initialized");
|
|
420
1796
|
}
|
|
421
1797
|
/**
|
|
422
|
-
*
|
|
1798
|
+
* Wait for wallet discovery to complete if the wallet is not yet in the registry
|
|
1799
|
+
* This is needed for auto-connect when the last wallet was an external wallet
|
|
423
1800
|
*/
|
|
1801
|
+
async waitForWalletDiscovery(walletId) {
|
|
1802
|
+
if (this.walletRegistry.has(walletId)) {
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet not found in registry, waiting for discovery", {
|
|
1806
|
+
walletId
|
|
1807
|
+
});
|
|
1808
|
+
try {
|
|
1809
|
+
await this.walletRegistry.discover(this.addressTypes);
|
|
1810
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet discovery completed", { walletId });
|
|
1811
|
+
} catch (error) {
|
|
1812
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Wallet discovery failed", {
|
|
1813
|
+
walletId,
|
|
1814
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
424
1818
|
get solana() {
|
|
425
|
-
if (!this.addressTypes.includes(
|
|
1819
|
+
if (!this.addressTypes.includes(import_client3.AddressType.solana)) {
|
|
426
1820
|
throw new Error("Solana not enabled for this provider");
|
|
427
1821
|
}
|
|
428
|
-
|
|
429
|
-
|
|
1822
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
1823
|
+
const walletInfo = this.walletRegistry.getById(walletId);
|
|
1824
|
+
if (!walletInfo) {
|
|
1825
|
+
const registry = this.walletRegistry;
|
|
1826
|
+
if (registry.discoveryPromise) {
|
|
1827
|
+
throw new Error(
|
|
1828
|
+
`Wallet "${walletId}" not found. Wallet discovery is still in progress. Please wait for sdk.discoverWallets() to complete before accessing chain properties.`
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
throw new Error(
|
|
1832
|
+
`Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
if (!walletInfo.providers?.solana) {
|
|
1836
|
+
throw new Error(
|
|
1837
|
+
`Selected wallet "${walletInfo.name}" does not support Solana. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Solana in addressTypes.`
|
|
1838
|
+
);
|
|
430
1839
|
}
|
|
431
|
-
return
|
|
1840
|
+
return walletInfo.providers.solana;
|
|
432
1841
|
}
|
|
433
1842
|
/**
|
|
434
1843
|
* Access to Ethereum chain operations
|
|
435
1844
|
*/
|
|
436
1845
|
get ethereum() {
|
|
437
|
-
if (!this.addressTypes.includes(
|
|
1846
|
+
if (!this.addressTypes.includes(import_client3.AddressType.ethereum)) {
|
|
438
1847
|
throw new Error("Ethereum not enabled for this provider");
|
|
439
1848
|
}
|
|
440
|
-
|
|
441
|
-
|
|
1849
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
1850
|
+
const walletInfo = this.walletRegistry.getById(walletId);
|
|
1851
|
+
if (!walletInfo) {
|
|
1852
|
+
const registry = this.walletRegistry;
|
|
1853
|
+
if (registry.discoveryPromise) {
|
|
1854
|
+
throw new Error(
|
|
1855
|
+
`Wallet "${walletId}" not found. Wallet discovery is still in progress. Please wait for sdk.discoverWallets() to complete before accessing chain properties.`
|
|
1856
|
+
);
|
|
1857
|
+
}
|
|
1858
|
+
throw new Error(
|
|
1859
|
+
`Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
if (!walletInfo.providers?.ethereum) {
|
|
1863
|
+
throw new Error(
|
|
1864
|
+
`Selected wallet "${walletInfo.name}" does not support Ethereum. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Ethereum in addressTypes.`
|
|
1865
|
+
);
|
|
442
1866
|
}
|
|
443
|
-
return
|
|
1867
|
+
return walletInfo.providers.ethereum;
|
|
444
1868
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
1869
|
+
validateAndSelectWallet(requestedWalletId) {
|
|
1870
|
+
if (!this.walletRegistry.has(requestedWalletId)) {
|
|
1871
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Unknown injected wallet id requested", {
|
|
1872
|
+
walletId: requestedWalletId
|
|
1873
|
+
});
|
|
1874
|
+
throw new Error(`Unknown injected wallet id: ${requestedWalletId}`);
|
|
1875
|
+
}
|
|
1876
|
+
const walletInfo = this.walletRegistry.getById(requestedWalletId);
|
|
1877
|
+
if (!walletInfo || !walletInfo.providers) {
|
|
1878
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Wallet not available for connection", {
|
|
1879
|
+
walletId: requestedWalletId
|
|
1880
|
+
});
|
|
1881
|
+
throw new Error(`Wallet not available for connection: ${requestedWalletId}`);
|
|
1882
|
+
}
|
|
1883
|
+
this.selectedWalletId = requestedWalletId;
|
|
1884
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Selected injected wallet for connection", {
|
|
1885
|
+
walletId: requestedWalletId
|
|
450
1886
|
});
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
1887
|
+
return walletInfo;
|
|
1888
|
+
}
|
|
1889
|
+
async connectToWallet(walletInfo, options) {
|
|
1890
|
+
if (!walletInfo.providers) {
|
|
1891
|
+
const error = new Error(`Wallet adapter not available for wallet: ${this.selectedWalletId}`);
|
|
1892
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet adapter not available", { walletId: this.selectedWalletId });
|
|
1893
|
+
this.emit("connect_error", {
|
|
1894
|
+
error: error.message,
|
|
1895
|
+
source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
|
|
1896
|
+
});
|
|
1897
|
+
throw error;
|
|
1898
|
+
}
|
|
1899
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Connecting via wallet", {
|
|
1900
|
+
walletId: this.selectedWalletId,
|
|
1901
|
+
walletName: walletInfo.name,
|
|
1902
|
+
options
|
|
454
1903
|
});
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
1904
|
+
if (!options?.skipEventListeners) {
|
|
1905
|
+
this.setupExternalWalletEvents(walletInfo);
|
|
1906
|
+
if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
|
|
1907
|
+
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
1908
|
+
this.browserInjectedCleanupFunctions = [];
|
|
1909
|
+
this.setupBrowserInjectedEvents();
|
|
1910
|
+
this.eventsInitialized = true;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
const connectedAddresses = [];
|
|
1914
|
+
if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers?.solana) {
|
|
1915
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection", {
|
|
1916
|
+
walletId: this.selectedWalletId,
|
|
1917
|
+
walletName: walletInfo.name,
|
|
1918
|
+
onlyIfTrusted: options?.onlyIfTrusted
|
|
1919
|
+
});
|
|
1920
|
+
try {
|
|
1921
|
+
const result = await walletInfo.providers.solana.connect(
|
|
1922
|
+
options?.onlyIfTrusted ? { onlyIfTrusted: true } : void 0
|
|
1923
|
+
);
|
|
1924
|
+
const address = result.publicKey;
|
|
1925
|
+
connectedAddresses.push({
|
|
1926
|
+
addressType: import_client3.AddressType.solana,
|
|
1927
|
+
address
|
|
1928
|
+
});
|
|
1929
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", {
|
|
1930
|
+
address,
|
|
1931
|
+
walletId: this.selectedWalletId,
|
|
1932
|
+
walletName: walletInfo.name
|
|
1933
|
+
});
|
|
1934
|
+
} catch (err) {
|
|
1935
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", {
|
|
1936
|
+
error: err,
|
|
1937
|
+
walletId: this.selectedWalletId,
|
|
1938
|
+
walletName: walletInfo.name
|
|
1939
|
+
});
|
|
459
1940
|
this.emit("connect_error", {
|
|
460
|
-
error:
|
|
461
|
-
source: "manual-connect"
|
|
1941
|
+
error: err instanceof Error ? err.message : "Failed to connect",
|
|
1942
|
+
source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
|
|
462
1943
|
});
|
|
463
|
-
throw
|
|
1944
|
+
throw err;
|
|
464
1945
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
} catch (err) {
|
|
479
|
-
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
|
|
1946
|
+
}
|
|
1947
|
+
if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers?.ethereum) {
|
|
1948
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum connection", {
|
|
1949
|
+
walletId: this.selectedWalletId,
|
|
1950
|
+
walletName: walletInfo.name,
|
|
1951
|
+
silent: options?.silent
|
|
1952
|
+
});
|
|
1953
|
+
try {
|
|
1954
|
+
let accounts;
|
|
1955
|
+
if (options?.silent) {
|
|
1956
|
+
accounts = await walletInfo.providers.ethereum.request({ method: "eth_accounts" });
|
|
1957
|
+
} else {
|
|
1958
|
+
accounts = await walletInfo.providers.ethereum.connect();
|
|
480
1959
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
} catch (err) {
|
|
495
|
-
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
|
|
1960
|
+
if (accounts.length > 0) {
|
|
1961
|
+
connectedAddresses.push(
|
|
1962
|
+
...accounts.map((address) => ({
|
|
1963
|
+
addressType: import_client3.AddressType.ethereum,
|
|
1964
|
+
address
|
|
1965
|
+
}))
|
|
1966
|
+
);
|
|
1967
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum connected successfully", {
|
|
1968
|
+
addresses: accounts,
|
|
1969
|
+
walletId: this.selectedWalletId,
|
|
1970
|
+
walletName: walletInfo.name
|
|
1971
|
+
});
|
|
496
1972
|
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
1973
|
+
} catch (err) {
|
|
1974
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", {
|
|
1975
|
+
error: err,
|
|
1976
|
+
walletId: this.selectedWalletId,
|
|
1977
|
+
walletName: walletInfo.name
|
|
1978
|
+
});
|
|
500
1979
|
this.emit("connect_error", {
|
|
501
|
-
error:
|
|
502
|
-
source: "manual-connect"
|
|
1980
|
+
error: err instanceof Error ? err.message : "Failed to connect",
|
|
1981
|
+
source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
|
|
503
1982
|
});
|
|
504
|
-
throw
|
|
1983
|
+
throw err;
|
|
505
1984
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
addresses: this.addresses,
|
|
1985
|
+
}
|
|
1986
|
+
return connectedAddresses;
|
|
1987
|
+
}
|
|
1988
|
+
async finalizeConnection(connectedAddresses, authProvider, walletId) {
|
|
1989
|
+
if (connectedAddresses.length === 0) {
|
|
1990
|
+
const error = new Error("Failed to connect to any supported wallet provider");
|
|
1991
|
+
this.emit("connect_error", {
|
|
1992
|
+
error: error.message,
|
|
515
1993
|
source: "manual-connect"
|
|
516
1994
|
});
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
1995
|
+
throw error;
|
|
1996
|
+
}
|
|
1997
|
+
if (this.selectedWalletId) {
|
|
1998
|
+
this.setWalletState(this.selectedWalletId, {
|
|
1999
|
+
connected: true,
|
|
2000
|
+
addresses: connectedAddresses
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Finalized connection with addresses", {
|
|
2004
|
+
addressCount: connectedAddresses.length,
|
|
2005
|
+
addresses: connectedAddresses.map((addr) => ({
|
|
2006
|
+
type: addr.addressType,
|
|
2007
|
+
address: addr.address.substring(0, 10) + "..."
|
|
2008
|
+
}))
|
|
2009
|
+
});
|
|
2010
|
+
const authUserId = await this.getAuthUserId("manual-connect");
|
|
2011
|
+
try {
|
|
2012
|
+
localStorage.setItem(WAS_CONNECTED_KEY, WAS_CONNECTED_VALUE);
|
|
2013
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Set was-connected flag - auto-reconnect enabled");
|
|
2014
|
+
if (this.selectedWalletId) {
|
|
2015
|
+
localStorage.setItem(LAST_WALLET_ID_KEY, this.selectedWalletId);
|
|
2016
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Stored last injected wallet id", {
|
|
2017
|
+
walletId: this.selectedWalletId
|
|
523
2018
|
});
|
|
524
2019
|
}
|
|
2020
|
+
} catch (error) {
|
|
2021
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to persist injected provider state", { error });
|
|
2022
|
+
}
|
|
2023
|
+
const walletInfo = walletId ? this.walletRegistry.getById(walletId) : void 0;
|
|
2024
|
+
const wallet = walletInfo ? {
|
|
2025
|
+
id: walletInfo.id,
|
|
2026
|
+
name: walletInfo.name,
|
|
2027
|
+
icon: walletInfo.icon,
|
|
2028
|
+
addressTypes: walletInfo.addressTypes,
|
|
2029
|
+
rdns: walletInfo.rdns,
|
|
2030
|
+
discovery: walletInfo.discovery
|
|
2031
|
+
} : void 0;
|
|
2032
|
+
const result = {
|
|
2033
|
+
addresses: connectedAddresses,
|
|
2034
|
+
status: "completed",
|
|
2035
|
+
authUserId,
|
|
2036
|
+
authProvider,
|
|
2037
|
+
walletId,
|
|
2038
|
+
wallet
|
|
2039
|
+
};
|
|
2040
|
+
this.emit("connect", {
|
|
2041
|
+
addresses: connectedAddresses,
|
|
2042
|
+
source: "manual-connect",
|
|
2043
|
+
authUserId
|
|
2044
|
+
});
|
|
2045
|
+
return result;
|
|
2046
|
+
}
|
|
2047
|
+
async connect(authOptions) {
|
|
2048
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider connect", {
|
|
2049
|
+
addressTypes: this.addressTypes,
|
|
2050
|
+
provider: authOptions.provider
|
|
2051
|
+
});
|
|
2052
|
+
if (authOptions.provider !== "injected") {
|
|
2053
|
+
throw new Error(`Invalid provider for injected connection: ${authOptions.provider}. Must be "injected"`);
|
|
2054
|
+
}
|
|
2055
|
+
this.emit("connect_start", {
|
|
2056
|
+
source: "manual-connect",
|
|
2057
|
+
providerType: "injected"
|
|
2058
|
+
});
|
|
2059
|
+
try {
|
|
2060
|
+
const requestedWalletId = authOptions.walletId || "phantom";
|
|
2061
|
+
const walletInfo = this.validateAndSelectWallet(requestedWalletId);
|
|
2062
|
+
const connectedAddresses = await this.connectToWallet(walletInfo);
|
|
2063
|
+
return await this.finalizeConnection(connectedAddresses, "injected", this.selectedWalletId || void 0);
|
|
2064
|
+
} catch (error) {
|
|
2065
|
+
this.emit("connect_error", {
|
|
2066
|
+
error: error instanceof Error ? error.message : "Failed to connect",
|
|
2067
|
+
source: "manual-connect"
|
|
2068
|
+
});
|
|
525
2069
|
throw error;
|
|
526
2070
|
}
|
|
527
2071
|
}
|
|
528
2072
|
async disconnect() {
|
|
529
2073
|
debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
2074
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2075
|
+
if (walletInfo?.providers) {
|
|
2076
|
+
if (this.addressTypes.includes(import_client3.AddressType.solana) && walletInfo.providers.solana) {
|
|
2077
|
+
try {
|
|
2078
|
+
await walletInfo.providers.solana.disconnect();
|
|
2079
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
|
|
2080
|
+
} catch (err) {
|
|
2081
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
if (this.addressTypes.includes(import_client3.AddressType.ethereum) && walletInfo.providers.ethereum) {
|
|
2085
|
+
try {
|
|
2086
|
+
await walletInfo.providers.ethereum.disconnect();
|
|
2087
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
|
|
2088
|
+
} catch (err) {
|
|
2089
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Ethereum", { error: err });
|
|
2090
|
+
}
|
|
536
2091
|
}
|
|
537
|
-
}
|
|
538
|
-
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
539
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected (no-op)");
|
|
540
2092
|
}
|
|
541
2093
|
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
542
2094
|
this.browserInjectedCleanupFunctions = [];
|
|
543
|
-
this.
|
|
544
|
-
|
|
2095
|
+
if (this.selectedWalletId) {
|
|
2096
|
+
this.externalWalletEventListenersSetup.delete(this.selectedWalletId);
|
|
2097
|
+
this.setWalletState(this.selectedWalletId, {
|
|
2098
|
+
connected: false,
|
|
2099
|
+
addresses: []
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
try {
|
|
2103
|
+
localStorage.removeItem(WAS_CONNECTED_KEY);
|
|
2104
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Cleared was connected flag to prevent auto-reconnect");
|
|
2105
|
+
} catch (error) {
|
|
2106
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to clear was-connected flag", { error });
|
|
2107
|
+
}
|
|
545
2108
|
this.emit("disconnect", {
|
|
546
2109
|
source: "manual-disconnect"
|
|
547
2110
|
});
|
|
548
2111
|
debug.info(DebugCategory.INJECTED_PROVIDER, "Injected provider disconnected successfully");
|
|
549
2112
|
}
|
|
550
2113
|
/**
|
|
551
|
-
* Attempt auto-connection
|
|
552
|
-
*
|
|
2114
|
+
* Attempt auto-connection if user was previously connected
|
|
2115
|
+
* Only reconnects if the user connected before and didn't explicitly disconnect
|
|
553
2116
|
* Should be called after setting up event listeners
|
|
554
2117
|
*/
|
|
555
2118
|
async autoConnect() {
|
|
556
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting auto-connect
|
|
2119
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting auto-connect");
|
|
2120
|
+
let lastWalletId = null;
|
|
2121
|
+
try {
|
|
2122
|
+
const wasConnected = localStorage.getItem(WAS_CONNECTED_KEY);
|
|
2123
|
+
if (wasConnected !== WAS_CONNECTED_VALUE) {
|
|
2124
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Skipping auto-connect: user was not previously connected");
|
|
2125
|
+
return;
|
|
2126
|
+
}
|
|
2127
|
+
lastWalletId = localStorage.getItem(LAST_WALLET_ID_KEY);
|
|
2128
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "User was previously connected, attempting auto-connect", {
|
|
2129
|
+
lastWalletId: lastWalletId || "phantom"
|
|
2130
|
+
});
|
|
2131
|
+
} catch (error) {
|
|
2132
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to check was-connected flag", { error });
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
557
2135
|
this.emit("connect_start", {
|
|
558
2136
|
source: "auto-connect",
|
|
559
2137
|
providerType: "injected"
|
|
560
2138
|
});
|
|
561
2139
|
try {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
2140
|
+
const walletId = lastWalletId || "phantom";
|
|
2141
|
+
await this.waitForWalletDiscovery(walletId);
|
|
2142
|
+
const walletInfo = this.validateAndSelectWallet(walletId);
|
|
2143
|
+
let connectedAddresses = [];
|
|
2144
|
+
try {
|
|
2145
|
+
connectedAddresses = await this.connectToWallet(walletInfo, {
|
|
2146
|
+
onlyIfTrusted: true,
|
|
2147
|
+
silent: true,
|
|
2148
|
+
skipEventListeners: true
|
|
2149
|
+
// Set up listeners only if connection succeeds
|
|
2150
|
+
});
|
|
2151
|
+
} catch (err) {
|
|
2152
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed (expected if not trusted)", {
|
|
2153
|
+
error: err,
|
|
2154
|
+
walletId: this.selectedWalletId
|
|
567
2155
|
});
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
const connectedAddresses = [];
|
|
571
|
-
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
572
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana auto-connect");
|
|
573
|
-
try {
|
|
574
|
-
const publicKey = await this.phantom.solana.connect({ onlyIfTrusted: true });
|
|
575
|
-
if (publicKey) {
|
|
576
|
-
connectedAddresses.push({
|
|
577
|
-
addressType: import_client4.AddressType.solana,
|
|
578
|
-
address: publicKey
|
|
579
|
-
});
|
|
580
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana auto-connected successfully", { address: publicKey });
|
|
581
|
-
}
|
|
582
|
-
} catch (err) {
|
|
583
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana auto-connect failed (expected if not trusted)", { error: err });
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
587
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum auto-connect");
|
|
588
|
-
try {
|
|
589
|
-
const accounts = await this.phantom.ethereum.connect({ onlyIfTrusted: true });
|
|
590
|
-
if (accounts && accounts.length > 0) {
|
|
591
|
-
connectedAddresses.push(
|
|
592
|
-
...accounts.map((address) => ({
|
|
593
|
-
addressType: import_client4.AddressType.ethereum,
|
|
594
|
-
address
|
|
595
|
-
}))
|
|
596
|
-
);
|
|
597
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connected successfully", { addresses: accounts });
|
|
598
|
-
}
|
|
599
|
-
} catch (err) {
|
|
600
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connect failed (expected if not trusted)", { error: err });
|
|
601
|
-
}
|
|
602
2156
|
}
|
|
603
2157
|
if (connectedAddresses.length === 0) {
|
|
604
2158
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed: no trusted connections available");
|
|
@@ -608,15 +2162,33 @@ var InjectedProvider = class {
|
|
|
608
2162
|
});
|
|
609
2163
|
return;
|
|
610
2164
|
}
|
|
611
|
-
this.
|
|
612
|
-
this.
|
|
2165
|
+
this.setupExternalWalletEvents(walletInfo);
|
|
2166
|
+
if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
|
|
2167
|
+
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
2168
|
+
this.browserInjectedCleanupFunctions = [];
|
|
2169
|
+
this.setupBrowserInjectedEvents();
|
|
2170
|
+
this.eventsInitialized = true;
|
|
2171
|
+
}
|
|
2172
|
+
if (this.selectedWalletId) {
|
|
2173
|
+
this.setWalletState(this.selectedWalletId, {
|
|
2174
|
+
connected: true,
|
|
2175
|
+
addresses: connectedAddresses
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
2178
|
+
const authUserId = await this.getAuthUserId("auto-connect");
|
|
613
2179
|
this.emit("connect", {
|
|
614
|
-
addresses:
|
|
615
|
-
source: "auto-connect"
|
|
2180
|
+
addresses: connectedAddresses,
|
|
2181
|
+
source: "auto-connect",
|
|
2182
|
+
authUserId
|
|
616
2183
|
});
|
|
617
2184
|
debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
|
|
618
2185
|
addressCount: connectedAddresses.length,
|
|
619
|
-
addresses: connectedAddresses.map((addr) => ({
|
|
2186
|
+
addresses: connectedAddresses.map((addr) => ({
|
|
2187
|
+
type: addr.addressType,
|
|
2188
|
+
address: addr.address.substring(0, 8) + "..."
|
|
2189
|
+
})),
|
|
2190
|
+
walletId: this.selectedWalletId,
|
|
2191
|
+
authUserId
|
|
620
2192
|
});
|
|
621
2193
|
} catch (error) {
|
|
622
2194
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed with error", {
|
|
@@ -628,28 +2200,103 @@ var InjectedProvider = class {
|
|
|
628
2200
|
});
|
|
629
2201
|
}
|
|
630
2202
|
}
|
|
2203
|
+
getWalletState(walletId) {
|
|
2204
|
+
if (!this.walletStates.has(walletId)) {
|
|
2205
|
+
this.walletStates.set(walletId, { connected: false, addresses: [] });
|
|
2206
|
+
}
|
|
2207
|
+
return this.walletStates.get(walletId);
|
|
2208
|
+
}
|
|
2209
|
+
setWalletState(walletId, state) {
|
|
2210
|
+
this.walletStates.set(walletId, state);
|
|
2211
|
+
}
|
|
631
2212
|
getAddresses() {
|
|
632
|
-
|
|
2213
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2214
|
+
return this.getWalletState(walletId).addresses;
|
|
2215
|
+
}
|
|
2216
|
+
/**
|
|
2217
|
+
* Get enabled address types for the current selected wallet
|
|
2218
|
+
* - For Phantom: returns config.addressTypes
|
|
2219
|
+
* - For external wallets: returns the wallet's addressTypes from registry
|
|
2220
|
+
*/
|
|
2221
|
+
getEnabledAddressTypes() {
|
|
2222
|
+
if (!this.selectedWalletId || this.selectedWalletId === "phantom") {
|
|
2223
|
+
return this.addressTypes;
|
|
2224
|
+
}
|
|
2225
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId);
|
|
2226
|
+
if (walletInfo) {
|
|
2227
|
+
return walletInfo.addressTypes;
|
|
2228
|
+
}
|
|
2229
|
+
return this.addressTypes;
|
|
633
2230
|
}
|
|
634
2231
|
isConnected() {
|
|
635
|
-
|
|
2232
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2233
|
+
return this.getWalletState(walletId).connected;
|
|
636
2234
|
}
|
|
637
|
-
// AutoConfirm methods - only available for
|
|
2235
|
+
// AutoConfirm methods - only available for Phantom wallet
|
|
638
2236
|
async enableAutoConfirm(params) {
|
|
2237
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2238
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2239
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2240
|
+
}
|
|
639
2241
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Enabling autoConfirm", { params });
|
|
640
|
-
return await
|
|
2242
|
+
return await walletInfo.phantomInstance.autoConfirm.autoConfirmEnable(params);
|
|
641
2243
|
}
|
|
642
2244
|
async disableAutoConfirm() {
|
|
2245
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2246
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2247
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2248
|
+
}
|
|
643
2249
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Disabling autoConfirm");
|
|
644
|
-
await
|
|
2250
|
+
await walletInfo.phantomInstance.autoConfirm.autoConfirmDisable();
|
|
645
2251
|
}
|
|
646
2252
|
async getAutoConfirmStatus() {
|
|
2253
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2254
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2255
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2256
|
+
}
|
|
647
2257
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Getting autoConfirm status");
|
|
648
|
-
return await
|
|
2258
|
+
return await walletInfo.phantomInstance.autoConfirm.autoConfirmStatus();
|
|
649
2259
|
}
|
|
650
2260
|
async getSupportedAutoConfirmChains() {
|
|
2261
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2262
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2263
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2264
|
+
}
|
|
651
2265
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Getting supported autoConfirm chains");
|
|
652
|
-
return await
|
|
2266
|
+
return await walletInfo.phantomInstance.autoConfirm.autoConfirmSupportedChains();
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Helper method to get authUserId from window.phantom.app.getUser()
|
|
2270
|
+
* Returns undefined if the method is not available or fails, or if wallet is not Phantom
|
|
2271
|
+
*/
|
|
2272
|
+
async getAuthUserId(context) {
|
|
2273
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2274
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2275
|
+
return void 0;
|
|
2276
|
+
}
|
|
2277
|
+
try {
|
|
2278
|
+
if (window.phantom?.app?.getUser) {
|
|
2279
|
+
const userInfo = await window.phantom.app.getUser();
|
|
2280
|
+
const authUserId = userInfo?.authUserId;
|
|
2281
|
+
if (authUserId) {
|
|
2282
|
+
debug.log(
|
|
2283
|
+
DebugCategory.INJECTED_PROVIDER,
|
|
2284
|
+
`Retrieved authUserId from window.phantom.app.getUser() during ${context}`,
|
|
2285
|
+
{
|
|
2286
|
+
authUserId
|
|
2287
|
+
}
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
2290
|
+
return authUserId;
|
|
2291
|
+
}
|
|
2292
|
+
} catch (error) {
|
|
2293
|
+
debug.log(
|
|
2294
|
+
DebugCategory.INJECTED_PROVIDER,
|
|
2295
|
+
`Failed to get user info during ${context} (method may not be supported)`,
|
|
2296
|
+
{ error }
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
return void 0;
|
|
653
2300
|
}
|
|
654
2301
|
// Event management methods - implementing unified event interface
|
|
655
2302
|
on(event, callback) {
|
|
@@ -690,132 +2337,245 @@ var InjectedProvider = class {
|
|
|
690
2337
|
}
|
|
691
2338
|
}
|
|
692
2339
|
setupBrowserInjectedEvents() {
|
|
693
|
-
|
|
694
|
-
if (
|
|
695
|
-
|
|
2340
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2341
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2342
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Skipping browser-injected-sdk event setup - not Phantom wallet");
|
|
2343
|
+
return;
|
|
696
2344
|
}
|
|
697
|
-
|
|
698
|
-
|
|
2345
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
|
|
2346
|
+
if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
|
|
2347
|
+
if (this.addressTypes.includes(import_client3.AddressType.solana)) {
|
|
2348
|
+
this.setupSolanaEvents(walletInfo.phantomInstance);
|
|
2349
|
+
}
|
|
2350
|
+
if (this.addressTypes.includes(import_client3.AddressType.ethereum)) {
|
|
2351
|
+
this.setupEthereumEvents(walletInfo.phantomInstance);
|
|
2352
|
+
}
|
|
699
2353
|
}
|
|
700
2354
|
}
|
|
701
|
-
setupSolanaEvents() {
|
|
2355
|
+
setupSolanaEvents(phantom) {
|
|
702
2356
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
|
|
703
|
-
const handleSolanaConnect = (publicKey) => {
|
|
2357
|
+
const handleSolanaConnect = async (publicKey) => {
|
|
704
2358
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
2359
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2360
|
+
const state = this.getWalletState(walletId);
|
|
2361
|
+
const solanaAddress = { addressType: import_client3.AddressType.solana, address: publicKey };
|
|
2362
|
+
const hasSolana = state.addresses.some((addr) => addr.addressType === import_client3.AddressType.solana);
|
|
2363
|
+
const newAddresses = hasSolana ? state.addresses.map((addr) => addr.addressType === import_client3.AddressType.solana ? solanaAddress : addr) : [...state.addresses, solanaAddress];
|
|
2364
|
+
this.setWalletState(walletId, {
|
|
2365
|
+
connected: true,
|
|
2366
|
+
addresses: newAddresses
|
|
2367
|
+
});
|
|
2368
|
+
const authUserId = await this.getAuthUserId("Solana connect event");
|
|
710
2369
|
this.emit("connect", {
|
|
711
|
-
addresses:
|
|
712
|
-
source: "injected-extension"
|
|
2370
|
+
addresses: newAddresses,
|
|
2371
|
+
source: "injected-extension",
|
|
2372
|
+
authUserId
|
|
713
2373
|
});
|
|
714
2374
|
};
|
|
715
2375
|
const handleSolanaDisconnect = () => {
|
|
716
2376
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
|
|
717
|
-
|
|
718
|
-
|
|
2377
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2378
|
+
const state = this.getWalletState(walletId);
|
|
2379
|
+
const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
|
|
2380
|
+
this.setWalletState(walletId, {
|
|
2381
|
+
connected: filteredAddresses.length > 0,
|
|
2382
|
+
addresses: filteredAddresses
|
|
2383
|
+
});
|
|
719
2384
|
this.emit("disconnect", {
|
|
720
2385
|
source: "injected-extension"
|
|
721
2386
|
});
|
|
722
2387
|
};
|
|
723
|
-
const handleSolanaAccountChanged = (publicKey) => {
|
|
2388
|
+
const handleSolanaAccountChanged = async (publicKey) => {
|
|
724
2389
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}
|
|
2390
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2391
|
+
const state = this.getWalletState(walletId);
|
|
2392
|
+
const solanaIndex = state.addresses.findIndex((addr) => addr.addressType === import_client3.AddressType.solana);
|
|
2393
|
+
const newAddresses = solanaIndex >= 0 ? state.addresses.map(
|
|
2394
|
+
(addr, idx) => idx === solanaIndex ? { addressType: import_client3.AddressType.solana, address: publicKey } : addr
|
|
2395
|
+
) : [...state.addresses, { addressType: import_client3.AddressType.solana, address: publicKey }];
|
|
2396
|
+
this.setWalletState(walletId, {
|
|
2397
|
+
connected: true,
|
|
2398
|
+
addresses: newAddresses
|
|
2399
|
+
});
|
|
2400
|
+
const authUserId = await this.getAuthUserId("Solana account changed event");
|
|
731
2401
|
this.emit("connect", {
|
|
732
|
-
addresses:
|
|
733
|
-
source: "injected-extension-account-change"
|
|
2402
|
+
addresses: newAddresses,
|
|
2403
|
+
source: "injected-extension-account-change",
|
|
2404
|
+
authUserId
|
|
734
2405
|
});
|
|
735
2406
|
};
|
|
736
|
-
const cleanupConnect =
|
|
737
|
-
const cleanupDisconnect =
|
|
738
|
-
const cleanupAccountChanged =
|
|
2407
|
+
const cleanupConnect = phantom.solana.addEventListener("connect", handleSolanaConnect);
|
|
2408
|
+
const cleanupDisconnect = phantom.solana.addEventListener("disconnect", handleSolanaDisconnect);
|
|
2409
|
+
const cleanupAccountChanged = phantom.solana.addEventListener("accountChanged", handleSolanaAccountChanged);
|
|
739
2410
|
this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountChanged);
|
|
740
2411
|
}
|
|
741
|
-
setupEthereumEvents() {
|
|
2412
|
+
setupEthereumEvents(phantom) {
|
|
742
2413
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
|
|
743
|
-
const handleEthereumConnect = (accounts) => {
|
|
2414
|
+
const handleEthereumConnect = async (accounts) => {
|
|
744
2415
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
}
|
|
754
|
-
|
|
2416
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2417
|
+
const state = this.getWalletState(walletId);
|
|
2418
|
+
const ethAddresses = accounts.map((address) => ({ addressType: import_client3.AddressType.ethereum, address }));
|
|
2419
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
|
|
2420
|
+
const newAddresses = [...otherAddresses, ...ethAddresses];
|
|
2421
|
+
this.setWalletState(walletId, {
|
|
2422
|
+
connected: true,
|
|
2423
|
+
addresses: newAddresses
|
|
2424
|
+
});
|
|
2425
|
+
const authUserId = await this.getAuthUserId("Ethereum connect event");
|
|
755
2426
|
this.emit("connect", {
|
|
756
|
-
addresses:
|
|
757
|
-
source: "injected-extension"
|
|
2427
|
+
addresses: newAddresses,
|
|
2428
|
+
source: "injected-extension",
|
|
2429
|
+
authUserId
|
|
758
2430
|
});
|
|
759
2431
|
};
|
|
760
2432
|
const handleEthereumDisconnect = () => {
|
|
761
2433
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
|
|
762
|
-
|
|
763
|
-
|
|
2434
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2435
|
+
const state = this.getWalletState(walletId);
|
|
2436
|
+
const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
|
|
2437
|
+
this.setWalletState(walletId, {
|
|
2438
|
+
connected: filteredAddresses.length > 0,
|
|
2439
|
+
addresses: filteredAddresses
|
|
2440
|
+
});
|
|
764
2441
|
this.emit("disconnect", {
|
|
765
2442
|
source: "injected-extension"
|
|
766
2443
|
});
|
|
767
2444
|
};
|
|
768
|
-
const handleEthereumAccountsChanged = (accounts) => {
|
|
2445
|
+
const handleEthereumAccountsChanged = async (accounts) => {
|
|
769
2446
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts });
|
|
770
|
-
|
|
2447
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2448
|
+
const state = this.getWalletState(walletId);
|
|
2449
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
|
|
771
2450
|
if (accounts && accounts.length > 0) {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
);
|
|
2451
|
+
const ethAddresses = accounts.map((address) => ({ addressType: import_client3.AddressType.ethereum, address }));
|
|
2452
|
+
const newAddresses = [...otherAddresses, ...ethAddresses];
|
|
2453
|
+
this.setWalletState(walletId, {
|
|
2454
|
+
connected: true,
|
|
2455
|
+
addresses: newAddresses
|
|
2456
|
+
});
|
|
2457
|
+
const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
|
|
778
2458
|
this.emit("connect", {
|
|
779
|
-
addresses:
|
|
780
|
-
source: "injected-extension-account-change"
|
|
2459
|
+
addresses: newAddresses,
|
|
2460
|
+
source: "injected-extension-account-change",
|
|
2461
|
+
authUserId
|
|
781
2462
|
});
|
|
782
2463
|
} else {
|
|
783
|
-
this.
|
|
2464
|
+
this.setWalletState(walletId, {
|
|
2465
|
+
connected: otherAddresses.length > 0,
|
|
2466
|
+
addresses: otherAddresses
|
|
2467
|
+
});
|
|
784
2468
|
this.emit("disconnect", {
|
|
785
2469
|
source: "injected-extension-account-change"
|
|
786
2470
|
});
|
|
787
2471
|
}
|
|
788
2472
|
};
|
|
789
|
-
const cleanupConnect =
|
|
790
|
-
const cleanupDisconnect =
|
|
791
|
-
const cleanupAccountsChanged =
|
|
792
|
-
"accountsChanged",
|
|
793
|
-
handleEthereumAccountsChanged
|
|
794
|
-
);
|
|
2473
|
+
const cleanupConnect = phantom.ethereum.addEventListener("connect", handleEthereumConnect);
|
|
2474
|
+
const cleanupDisconnect = phantom.ethereum.addEventListener("disconnect", handleEthereumDisconnect);
|
|
2475
|
+
const cleanupAccountsChanged = phantom.ethereum.addEventListener("accountsChanged", handleEthereumAccountsChanged);
|
|
795
2476
|
this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountsChanged);
|
|
796
2477
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
this.
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
2478
|
+
setupExternalWalletEvents(walletInfo) {
|
|
2479
|
+
if (isPhantomWallet(walletInfo)) {
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
if (!this.selectedWalletId || this.externalWalletEventListenersSetup.has(this.selectedWalletId)) {
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up external wallet event listeners", {
|
|
2486
|
+
walletId: this.selectedWalletId
|
|
2487
|
+
});
|
|
2488
|
+
if (walletInfo.providers?.ethereum) {
|
|
2489
|
+
const handleExternalEthereumAccountsChanged = async (accounts) => {
|
|
2490
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum accounts changed event received", {
|
|
2491
|
+
walletId: this.selectedWalletId,
|
|
2492
|
+
accounts
|
|
2493
|
+
});
|
|
2494
|
+
const walletId = this.selectedWalletId;
|
|
2495
|
+
const state = this.getWalletState(walletId);
|
|
2496
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.ethereum);
|
|
2497
|
+
if (accounts && accounts.length > 0) {
|
|
2498
|
+
const ethAddresses = accounts.map((address) => ({ addressType: import_client3.AddressType.ethereum, address }));
|
|
2499
|
+
const newAddresses = [...otherAddresses, ...ethAddresses];
|
|
2500
|
+
this.setWalletState(walletId, {
|
|
2501
|
+
connected: true,
|
|
2502
|
+
addresses: newAddresses
|
|
2503
|
+
});
|
|
2504
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Updated Ethereum addresses after account change", {
|
|
2505
|
+
walletId,
|
|
2506
|
+
oldCount: 0,
|
|
2507
|
+
// We filtered them out
|
|
2508
|
+
newCount: accounts.length,
|
|
2509
|
+
addresses: newAddresses.filter((addr) => addr.addressType === import_client3.AddressType.ethereum)
|
|
2510
|
+
});
|
|
2511
|
+
const authUserId = await this.getAuthUserId("External wallet Ethereum accounts changed event");
|
|
2512
|
+
this.emit("connect", {
|
|
2513
|
+
addresses: newAddresses,
|
|
2514
|
+
source: "external-wallet-account-change",
|
|
2515
|
+
authUserId
|
|
2516
|
+
});
|
|
2517
|
+
} else {
|
|
2518
|
+
this.setWalletState(walletId, {
|
|
2519
|
+
connected: otherAddresses.length > 0,
|
|
2520
|
+
addresses: otherAddresses
|
|
2521
|
+
});
|
|
2522
|
+
this.emit("disconnect", {
|
|
2523
|
+
source: "external-wallet-account-change"
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
};
|
|
2527
|
+
if (typeof walletInfo.providers.ethereum.on === "function") {
|
|
2528
|
+
walletInfo.providers.ethereum.on("accountsChanged", handleExternalEthereumAccountsChanged);
|
|
2529
|
+
this.browserInjectedCleanupFunctions.push(() => {
|
|
2530
|
+
if (typeof walletInfo.providers?.ethereum?.off === "function") {
|
|
2531
|
+
walletInfo.providers.ethereum.off("accountsChanged", handleExternalEthereumAccountsChanged);
|
|
2532
|
+
}
|
|
2533
|
+
});
|
|
817
2534
|
}
|
|
818
|
-
}
|
|
2535
|
+
}
|
|
2536
|
+
if (walletInfo.providers?.solana) {
|
|
2537
|
+
const handleExternalSolanaAccountChanged = async (publicKey) => {
|
|
2538
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana account changed event received", {
|
|
2539
|
+
walletId: this.selectedWalletId,
|
|
2540
|
+
publicKey
|
|
2541
|
+
});
|
|
2542
|
+
const walletId = this.selectedWalletId;
|
|
2543
|
+
const state = this.getWalletState(walletId);
|
|
2544
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== import_client3.AddressType.solana);
|
|
2545
|
+
if (publicKey) {
|
|
2546
|
+
const newAddresses = [...otherAddresses, { addressType: import_client3.AddressType.solana, address: publicKey }];
|
|
2547
|
+
this.setWalletState(walletId, {
|
|
2548
|
+
connected: true,
|
|
2549
|
+
addresses: newAddresses
|
|
2550
|
+
});
|
|
2551
|
+
const authUserId = await this.getAuthUserId("External wallet Solana account changed event");
|
|
2552
|
+
this.emit("connect", {
|
|
2553
|
+
addresses: newAddresses,
|
|
2554
|
+
source: "external-wallet-account-change",
|
|
2555
|
+
authUserId
|
|
2556
|
+
});
|
|
2557
|
+
} else {
|
|
2558
|
+
this.setWalletState(walletId, {
|
|
2559
|
+
connected: otherAddresses.length > 0,
|
|
2560
|
+
addresses: otherAddresses
|
|
2561
|
+
});
|
|
2562
|
+
this.emit("disconnect", {
|
|
2563
|
+
source: "external-wallet-account-change"
|
|
2564
|
+
});
|
|
2565
|
+
}
|
|
2566
|
+
};
|
|
2567
|
+
if (typeof walletInfo.providers.solana.on === "function") {
|
|
2568
|
+
walletInfo.providers.solana.on("accountChanged", handleExternalSolanaAccountChanged);
|
|
2569
|
+
this.browserInjectedCleanupFunctions.push(() => {
|
|
2570
|
+
if (typeof walletInfo.providers?.solana?.off === "function") {
|
|
2571
|
+
walletInfo.providers.solana.off("accountChanged", handleExternalSolanaAccountChanged);
|
|
2572
|
+
}
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
if (this.selectedWalletId) {
|
|
2577
|
+
this.externalWalletEventListenersSetup.add(this.selectedWalletId);
|
|
2578
|
+
}
|
|
819
2579
|
}
|
|
820
2580
|
};
|
|
821
2581
|
|
|
@@ -897,7 +2657,48 @@ var BrowserStorage = class {
|
|
|
897
2657
|
resolve();
|
|
898
2658
|
};
|
|
899
2659
|
request.onerror = () => {
|
|
900
|
-
debug.error(DebugCategory.STORAGE, "Failed to clear session from IndexedDB", { error: request.error });
|
|
2660
|
+
debug.error(DebugCategory.STORAGE, "Failed to clear session from IndexedDB", { error: request.error });
|
|
2661
|
+
reject(request.error);
|
|
2662
|
+
};
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
async getShouldClearPreviousSession() {
|
|
2666
|
+
debug.log(DebugCategory.STORAGE, "Getting shouldClearPreviousSession flag from IndexedDB");
|
|
2667
|
+
const db = await this.getDB();
|
|
2668
|
+
return new Promise((resolve, reject) => {
|
|
2669
|
+
const transaction = db.transaction([this.storeName], "readonly");
|
|
2670
|
+
const store = transaction.objectStore(this.storeName);
|
|
2671
|
+
const request = store.get("shouldClearPreviousSession");
|
|
2672
|
+
request.onsuccess = () => {
|
|
2673
|
+
const shouldClear = request.result ?? false;
|
|
2674
|
+
debug.log(DebugCategory.STORAGE, "Retrieved shouldClearPreviousSession flag from IndexedDB", {
|
|
2675
|
+
shouldClear
|
|
2676
|
+
});
|
|
2677
|
+
resolve(shouldClear);
|
|
2678
|
+
};
|
|
2679
|
+
request.onerror = () => {
|
|
2680
|
+
debug.error(DebugCategory.STORAGE, "Failed to get shouldClearPreviousSession flag from IndexedDB", {
|
|
2681
|
+
error: request.error
|
|
2682
|
+
});
|
|
2683
|
+
reject(request.error);
|
|
2684
|
+
};
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
async setShouldClearPreviousSession(should) {
|
|
2688
|
+
debug.log(DebugCategory.STORAGE, "Setting shouldClearPreviousSession flag in IndexedDB", { should });
|
|
2689
|
+
const db = await this.getDB();
|
|
2690
|
+
return new Promise((resolve, reject) => {
|
|
2691
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
2692
|
+
const store = transaction.objectStore(this.storeName);
|
|
2693
|
+
const request = store.put(should, "shouldClearPreviousSession");
|
|
2694
|
+
request.onsuccess = () => {
|
|
2695
|
+
debug.log(DebugCategory.STORAGE, "Successfully set shouldClearPreviousSession flag in IndexedDB");
|
|
2696
|
+
resolve();
|
|
2697
|
+
};
|
|
2698
|
+
request.onerror = () => {
|
|
2699
|
+
debug.error(DebugCategory.STORAGE, "Failed to set shouldClearPreviousSession flag in IndexedDB", {
|
|
2700
|
+
error: request.error
|
|
2701
|
+
});
|
|
901
2702
|
reject(request.error);
|
|
902
2703
|
};
|
|
903
2704
|
});
|
|
@@ -915,6 +2716,147 @@ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
|
|
|
915
2716
|
|
|
916
2717
|
// src/providers/embedded/adapters/auth.ts
|
|
917
2718
|
var import_constants = require("@phantom/constants");
|
|
2719
|
+
|
|
2720
|
+
// src/utils/browser-detection.ts
|
|
2721
|
+
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
2722
|
+
let name = "unknown";
|
|
2723
|
+
let version = "unknown";
|
|
2724
|
+
if (!userAgent || typeof userAgent !== "string") {
|
|
2725
|
+
return { name, version, userAgent: "unknown" };
|
|
2726
|
+
}
|
|
2727
|
+
try {
|
|
2728
|
+
if (userAgent.includes("Edg/")) {
|
|
2729
|
+
name = "edge";
|
|
2730
|
+
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2731
|
+
if (match)
|
|
2732
|
+
version = match[1].split(".")[0];
|
|
2733
|
+
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
2734
|
+
name = "opera";
|
|
2735
|
+
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2736
|
+
if (match)
|
|
2737
|
+
version = match[1].split(".")[0];
|
|
2738
|
+
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
2739
|
+
name = "samsung";
|
|
2740
|
+
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2741
|
+
if (match)
|
|
2742
|
+
version = match[1].split(".")[0];
|
|
2743
|
+
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
2744
|
+
name = "duckduckgo";
|
|
2745
|
+
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2746
|
+
if (match)
|
|
2747
|
+
version = match[1].split(".")[0];
|
|
2748
|
+
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
2749
|
+
name = "brave";
|
|
2750
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2751
|
+
if (match)
|
|
2752
|
+
version = match[1].split(".")[0];
|
|
2753
|
+
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
2754
|
+
if (userAgent.includes("Chrome/")) {
|
|
2755
|
+
name = "chrome-mobile";
|
|
2756
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2757
|
+
if (match)
|
|
2758
|
+
version = match[1].split(".")[0];
|
|
2759
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
2760
|
+
name = "firefox-mobile";
|
|
2761
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2762
|
+
if (match)
|
|
2763
|
+
version = match[1].split(".")[0];
|
|
2764
|
+
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
2765
|
+
name = "safari-mobile";
|
|
2766
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2767
|
+
if (match)
|
|
2768
|
+
version = match[1].split(".")[0];
|
|
2769
|
+
} else {
|
|
2770
|
+
name = "mobile";
|
|
2771
|
+
}
|
|
2772
|
+
} else if (userAgent.includes("Chrome/")) {
|
|
2773
|
+
name = "chrome";
|
|
2774
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2775
|
+
if (match)
|
|
2776
|
+
version = match[1].split(".")[0];
|
|
2777
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
2778
|
+
name = "firefox";
|
|
2779
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2780
|
+
if (match)
|
|
2781
|
+
version = match[1].split(".")[0];
|
|
2782
|
+
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
2783
|
+
name = "safari";
|
|
2784
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
2785
|
+
if (match)
|
|
2786
|
+
version = match[1].split(".")[0];
|
|
2787
|
+
}
|
|
2788
|
+
if (name === "unknown") {
|
|
2789
|
+
const patterns = [
|
|
2790
|
+
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
2791
|
+
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
2792
|
+
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
2793
|
+
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
2794
|
+
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
2795
|
+
];
|
|
2796
|
+
for (const pattern of patterns) {
|
|
2797
|
+
const match = userAgent.match(pattern.regex);
|
|
2798
|
+
if (match) {
|
|
2799
|
+
name = pattern.name;
|
|
2800
|
+
version = match[1];
|
|
2801
|
+
break;
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
}
|
|
2807
|
+
return { name, version, userAgent };
|
|
2808
|
+
}
|
|
2809
|
+
function detectBrowser() {
|
|
2810
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
2811
|
+
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
2812
|
+
}
|
|
2813
|
+
const userAgent = window.navigator.userAgent;
|
|
2814
|
+
const hasBraveAPI = !!navigator.brave;
|
|
2815
|
+
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
2816
|
+
}
|
|
2817
|
+
function getPlatformName() {
|
|
2818
|
+
const { name, version } = detectBrowser();
|
|
2819
|
+
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
2820
|
+
}
|
|
2821
|
+
function getBrowserDisplayName() {
|
|
2822
|
+
const { name, version } = detectBrowser();
|
|
2823
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
2824
|
+
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
2825
|
+
}
|
|
2826
|
+
function isMobileDevice() {
|
|
2827
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
2828
|
+
return false;
|
|
2829
|
+
}
|
|
2830
|
+
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
2831
|
+
const mobilePatterns = [
|
|
2832
|
+
/android/,
|
|
2833
|
+
/iphone|ipad|ipod/,
|
|
2834
|
+
/blackberry/,
|
|
2835
|
+
/windows phone/,
|
|
2836
|
+
/mobile/,
|
|
2837
|
+
/tablet/,
|
|
2838
|
+
/silk/,
|
|
2839
|
+
/kindle/,
|
|
2840
|
+
/opera mini/,
|
|
2841
|
+
/opera mobi/
|
|
2842
|
+
];
|
|
2843
|
+
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
2844
|
+
let isSmallScreen = false;
|
|
2845
|
+
try {
|
|
2846
|
+
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
2847
|
+
} catch (error) {
|
|
2848
|
+
isSmallScreen = false;
|
|
2849
|
+
}
|
|
2850
|
+
let isTouchDevice = false;
|
|
2851
|
+
try {
|
|
2852
|
+
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
2853
|
+
} catch (error) {
|
|
2854
|
+
isTouchDevice = false;
|
|
2855
|
+
}
|
|
2856
|
+
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
// src/providers/embedded/adapters/auth.ts
|
|
918
2860
|
var BrowserAuthProvider = class {
|
|
919
2861
|
constructor(urlParamsAccessor) {
|
|
920
2862
|
this.urlParamsAccessor = urlParamsAccessor;
|
|
@@ -933,21 +2875,24 @@ var BrowserAuthProvider = class {
|
|
|
933
2875
|
}
|
|
934
2876
|
const phantomOptions = options;
|
|
935
2877
|
debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Starting Phantom Connect authentication", {
|
|
936
|
-
|
|
2878
|
+
publicKey: phantomOptions.publicKey,
|
|
937
2879
|
appId: phantomOptions.appId,
|
|
938
2880
|
provider: phantomOptions.provider,
|
|
939
|
-
authUrl: phantomOptions.authUrl
|
|
940
|
-
hasCustomData: !!phantomOptions.customAuthData
|
|
2881
|
+
authUrl: phantomOptions.authUrl
|
|
941
2882
|
});
|
|
942
2883
|
const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
|
|
943
2884
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
|
|
944
2885
|
const params = new URLSearchParams({
|
|
945
|
-
|
|
2886
|
+
public_key: phantomOptions.publicKey,
|
|
946
2887
|
app_id: phantomOptions.appId,
|
|
947
2888
|
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
|
|
948
2889
|
session_id: phantomOptions.sessionId,
|
|
949
|
-
|
|
950
|
-
|
|
2890
|
+
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
2891
|
+
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
2892
|
+
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
2893
|
+
sdk_version: "1.0.0",
|
|
2894
|
+
sdk_type: "browser",
|
|
2895
|
+
platform: detectBrowser().name
|
|
951
2896
|
});
|
|
952
2897
|
if (phantomOptions.provider) {
|
|
953
2898
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
|
|
@@ -958,12 +2903,8 @@ var BrowserAuthProvider = class {
|
|
|
958
2903
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
|
|
959
2904
|
params.append("provider", "google");
|
|
960
2905
|
}
|
|
961
|
-
if (phantomOptions.customAuthData) {
|
|
962
|
-
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Adding custom auth data");
|
|
963
|
-
params.append("authData", JSON.stringify(phantomOptions.customAuthData));
|
|
964
|
-
}
|
|
965
2906
|
const authContext = {
|
|
966
|
-
|
|
2907
|
+
publicKey: phantomOptions.publicKey,
|
|
967
2908
|
appId: phantomOptions.appId,
|
|
968
2909
|
provider: phantomOptions.provider,
|
|
969
2910
|
sessionId: phantomOptions.sessionId
|
|
@@ -972,14 +2913,14 @@ var BrowserAuthProvider = class {
|
|
|
972
2913
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Stored auth context in session storage", { authContext });
|
|
973
2914
|
const authUrl = `${baseUrl}?${params.toString()}`;
|
|
974
2915
|
debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Redirecting to Phantom Connect", { authUrl });
|
|
975
|
-
if (!authUrl.startsWith("https:")) {
|
|
2916
|
+
if (!authUrl.startsWith("https:") && !authUrl.startsWith("http://localhost")) {
|
|
976
2917
|
throw new Error("Invalid auth URL - only HTTPS URLs are allowed for authentication");
|
|
977
2918
|
}
|
|
978
2919
|
window.location.href = authUrl;
|
|
979
2920
|
resolve();
|
|
980
2921
|
});
|
|
981
2922
|
}
|
|
982
|
-
resumeAuthFromRedirect() {
|
|
2923
|
+
resumeAuthFromRedirect(provider) {
|
|
983
2924
|
try {
|
|
984
2925
|
const walletId = this.urlParamsAccessor.getParam("wallet_id");
|
|
985
2926
|
const sessionId = this.urlParamsAccessor.getParam("session_id");
|
|
@@ -1030,10 +2971,37 @@ var BrowserAuthProvider = class {
|
|
|
1030
2971
|
sessionId,
|
|
1031
2972
|
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : void 0
|
|
1032
2973
|
});
|
|
2974
|
+
const organizationId = this.urlParamsAccessor.getParam("organization_id");
|
|
2975
|
+
const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
|
|
2976
|
+
const authUserId = this.urlParamsAccessor.getParam("auth_user_id");
|
|
2977
|
+
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
|
|
2978
|
+
walletId,
|
|
2979
|
+
organizationId,
|
|
2980
|
+
sessionId,
|
|
2981
|
+
accountDerivationIndex,
|
|
2982
|
+
expiresInMs,
|
|
2983
|
+
authUserId
|
|
2984
|
+
});
|
|
2985
|
+
if (!organizationId) {
|
|
2986
|
+
debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
|
|
2987
|
+
throw new Error("Missing organization_id in auth response");
|
|
2988
|
+
}
|
|
2989
|
+
if (organizationId.startsWith("temp-")) {
|
|
2990
|
+
debug.warn(
|
|
2991
|
+
DebugCategory.PHANTOM_CONNECT_AUTH,
|
|
2992
|
+
"Received temporary organization_id, server may not be configured properly",
|
|
2993
|
+
{
|
|
2994
|
+
organizationId
|
|
2995
|
+
}
|
|
2996
|
+
);
|
|
2997
|
+
}
|
|
1033
2998
|
return {
|
|
1034
2999
|
walletId,
|
|
1035
|
-
|
|
1036
|
-
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) :
|
|
3000
|
+
organizationId,
|
|
3001
|
+
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
3002
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
|
|
3003
|
+
authUserId: authUserId || void 0,
|
|
3004
|
+
provider
|
|
1037
3005
|
};
|
|
1038
3006
|
} catch (error) {
|
|
1039
3007
|
sessionStorage.removeItem("phantom-auth-context");
|
|
@@ -1042,160 +3010,120 @@ var BrowserAuthProvider = class {
|
|
|
1042
3010
|
}
|
|
1043
3011
|
};
|
|
1044
3012
|
|
|
1045
|
-
// src/providers/embedded/adapters/
|
|
1046
|
-
var
|
|
1047
|
-
info(category, message, data) {
|
|
1048
|
-
debug.info(category, message, data);
|
|
1049
|
-
}
|
|
1050
|
-
warn(category, message, data) {
|
|
1051
|
-
debug.warn(category, message, data);
|
|
1052
|
-
}
|
|
1053
|
-
error(category, message, data) {
|
|
1054
|
-
debug.error(category, message, data);
|
|
1055
|
-
}
|
|
1056
|
-
log(category, message, data) {
|
|
1057
|
-
debug.log(category, message, data);
|
|
1058
|
-
}
|
|
1059
|
-
};
|
|
3013
|
+
// src/providers/embedded/adapters/phantom-app.ts
|
|
3014
|
+
var import_browser_injected_sdk4 = require("@phantom/browser-injected-sdk");
|
|
1060
3015
|
|
|
1061
|
-
// src/
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
if (!
|
|
1066
|
-
return
|
|
3016
|
+
// src/isPhantomLoginAvailable.ts
|
|
3017
|
+
var import_browser_injected_sdk3 = require("@phantom/browser-injected-sdk");
|
|
3018
|
+
async function isPhantomLoginAvailable(timeoutMs = 3e3) {
|
|
3019
|
+
const extensionInstalled = await waitForExtension(timeoutMs);
|
|
3020
|
+
if (!extensionInstalled) {
|
|
3021
|
+
return false;
|
|
1067
3022
|
}
|
|
1068
3023
|
try {
|
|
1069
|
-
if (
|
|
1070
|
-
|
|
1071
|
-
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1072
|
-
if (match)
|
|
1073
|
-
version = match[1].split(".")[0];
|
|
1074
|
-
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
1075
|
-
name = "opera";
|
|
1076
|
-
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1077
|
-
if (match)
|
|
1078
|
-
version = match[1].split(".")[0];
|
|
1079
|
-
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
1080
|
-
name = "samsung";
|
|
1081
|
-
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1082
|
-
if (match)
|
|
1083
|
-
version = match[1].split(".")[0];
|
|
1084
|
-
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
1085
|
-
name = "duckduckgo";
|
|
1086
|
-
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1087
|
-
if (match)
|
|
1088
|
-
version = match[1].split(".")[0];
|
|
1089
|
-
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
1090
|
-
name = "brave";
|
|
1091
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1092
|
-
if (match)
|
|
1093
|
-
version = match[1].split(".")[0];
|
|
1094
|
-
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
1095
|
-
if (userAgent.includes("Chrome/")) {
|
|
1096
|
-
name = "chrome-mobile";
|
|
1097
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1098
|
-
if (match)
|
|
1099
|
-
version = match[1].split(".")[0];
|
|
1100
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1101
|
-
name = "firefox-mobile";
|
|
1102
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1103
|
-
if (match)
|
|
1104
|
-
version = match[1].split(".")[0];
|
|
1105
|
-
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
1106
|
-
name = "safari-mobile";
|
|
1107
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1108
|
-
if (match)
|
|
1109
|
-
version = match[1].split(".")[0];
|
|
1110
|
-
} else {
|
|
1111
|
-
name = "mobile";
|
|
1112
|
-
}
|
|
1113
|
-
} else if (userAgent.includes("Chrome/")) {
|
|
1114
|
-
name = "chrome";
|
|
1115
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1116
|
-
if (match)
|
|
1117
|
-
version = match[1].split(".")[0];
|
|
1118
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1119
|
-
name = "firefox";
|
|
1120
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1121
|
-
if (match)
|
|
1122
|
-
version = match[1].split(".")[0];
|
|
1123
|
-
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
1124
|
-
name = "safari";
|
|
1125
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1126
|
-
if (match)
|
|
1127
|
-
version = match[1].split(".")[0];
|
|
3024
|
+
if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
|
|
3025
|
+
return false;
|
|
1128
3026
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
3027
|
+
const response = await window.phantom.app.features();
|
|
3028
|
+
if (!Array.isArray(response.features)) {
|
|
3029
|
+
return false;
|
|
3030
|
+
}
|
|
3031
|
+
return response.features.includes("phantom_login");
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
console.error("Error checking Phantom extension features", error);
|
|
3034
|
+
return false;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
async function waitForExtension(timeoutMs) {
|
|
3038
|
+
return new Promise((resolve) => {
|
|
3039
|
+
const startTime = Date.now();
|
|
3040
|
+
const checkInterval = 100;
|
|
3041
|
+
const checkForExtension = () => {
|
|
3042
|
+
try {
|
|
3043
|
+
if ((0, import_browser_injected_sdk3.isPhantomExtensionInstalled)()) {
|
|
3044
|
+
resolve(true);
|
|
3045
|
+
return;
|
|
1143
3046
|
}
|
|
3047
|
+
} catch (error) {
|
|
3048
|
+
}
|
|
3049
|
+
const elapsed = Date.now() - startTime;
|
|
3050
|
+
if (elapsed >= timeoutMs) {
|
|
3051
|
+
resolve(false);
|
|
3052
|
+
return;
|
|
1144
3053
|
}
|
|
3054
|
+
setTimeout(checkForExtension, checkInterval);
|
|
3055
|
+
};
|
|
3056
|
+
checkForExtension();
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
3059
|
+
|
|
3060
|
+
// src/providers/embedded/adapters/phantom-app.ts
|
|
3061
|
+
var BrowserPhantomAppProvider = class {
|
|
3062
|
+
/**
|
|
3063
|
+
* Check if the Phantom extension is installed in the browser
|
|
3064
|
+
*/
|
|
3065
|
+
isAvailable() {
|
|
3066
|
+
return (0, import_browser_injected_sdk4.isPhantomExtensionInstalled)();
|
|
3067
|
+
}
|
|
3068
|
+
/**
|
|
3069
|
+
* Authenticate using the Phantom browser extension
|
|
3070
|
+
*/
|
|
3071
|
+
async authenticate(options) {
|
|
3072
|
+
if (!this.isAvailable()) {
|
|
3073
|
+
throw new Error(
|
|
3074
|
+
"Phantom extension is not installed. Please install the Phantom browser extension to use this authentication method."
|
|
3075
|
+
);
|
|
3076
|
+
}
|
|
3077
|
+
const loginAvailable = await isPhantomLoginAvailable();
|
|
3078
|
+
if (!loginAvailable) {
|
|
3079
|
+
throw new Error(
|
|
3080
|
+
"Phantom Login is not available. Please update your Phantom extension to use this authentication method."
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3083
|
+
try {
|
|
3084
|
+
if (!window.phantom?.app?.login) {
|
|
3085
|
+
throw new Error("Phantom extension login method not found");
|
|
3086
|
+
}
|
|
3087
|
+
const result = await window.phantom.app.login({
|
|
3088
|
+
publicKey: options.publicKey,
|
|
3089
|
+
appId: options.appId,
|
|
3090
|
+
sessionId: options.sessionId
|
|
3091
|
+
});
|
|
3092
|
+
if (!result || !result.walletId || !result.organizationId) {
|
|
3093
|
+
throw new Error("Invalid authentication response from Phantom extension");
|
|
3094
|
+
}
|
|
3095
|
+
return {
|
|
3096
|
+
walletId: result.walletId,
|
|
3097
|
+
organizationId: result.organizationId,
|
|
3098
|
+
provider: "phantom",
|
|
3099
|
+
accountDerivationIndex: result.accountDerivationIndex ?? 0,
|
|
3100
|
+
expiresInMs: result.expiresInMs ?? 0,
|
|
3101
|
+
authUserId: result.authUserId
|
|
3102
|
+
};
|
|
3103
|
+
} catch (error) {
|
|
3104
|
+
if (error instanceof Error) {
|
|
3105
|
+
throw error;
|
|
3106
|
+
}
|
|
3107
|
+
throw new Error(`Phantom extension authentication failed: ${String(error)}`);
|
|
1145
3108
|
}
|
|
1146
|
-
} catch (error) {
|
|
1147
3109
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
3110
|
+
};
|
|
3111
|
+
|
|
3112
|
+
// src/providers/embedded/adapters/logger.ts
|
|
3113
|
+
var BrowserLogger = class {
|
|
3114
|
+
info(category, message, data) {
|
|
3115
|
+
debug.info(category, message, data);
|
|
1153
3116
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1157
|
-
}
|
|
1158
|
-
function getPlatformName() {
|
|
1159
|
-
const { name, version } = detectBrowser();
|
|
1160
|
-
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1161
|
-
}
|
|
1162
|
-
function getBrowserDisplayName() {
|
|
1163
|
-
const { name, version } = detectBrowser();
|
|
1164
|
-
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1165
|
-
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1166
|
-
}
|
|
1167
|
-
function isMobileDevice() {
|
|
1168
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1169
|
-
return false;
|
|
3117
|
+
warn(category, message, data) {
|
|
3118
|
+
debug.warn(category, message, data);
|
|
1170
3119
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
/android/,
|
|
1174
|
-
/iphone|ipad|ipod/,
|
|
1175
|
-
/blackberry/,
|
|
1176
|
-
/windows phone/,
|
|
1177
|
-
/mobile/,
|
|
1178
|
-
/tablet/,
|
|
1179
|
-
/silk/,
|
|
1180
|
-
/kindle/,
|
|
1181
|
-
/opera mini/,
|
|
1182
|
-
/opera mobi/
|
|
1183
|
-
];
|
|
1184
|
-
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1185
|
-
let isSmallScreen = false;
|
|
1186
|
-
try {
|
|
1187
|
-
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1188
|
-
} catch (error) {
|
|
1189
|
-
isSmallScreen = false;
|
|
3120
|
+
error(category, message, data) {
|
|
3121
|
+
debug.error(category, message, data);
|
|
1190
3122
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1194
|
-
} catch (error) {
|
|
1195
|
-
isTouchDevice = false;
|
|
3123
|
+
log(category, message, data) {
|
|
3124
|
+
debug.log(category, message, data);
|
|
1196
3125
|
}
|
|
1197
|
-
|
|
1198
|
-
}
|
|
3126
|
+
};
|
|
1199
3127
|
|
|
1200
3128
|
// src/providers/embedded/index.ts
|
|
1201
3129
|
var import_constants2 = require("@phantom/constants");
|
|
@@ -1213,6 +3141,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1213
3141
|
const platform = {
|
|
1214
3142
|
storage: new BrowserStorage(),
|
|
1215
3143
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
3144
|
+
phantomAppProvider: new BrowserPhantomAppProvider(),
|
|
1216
3145
|
urlParamsAccessor,
|
|
1217
3146
|
stamper,
|
|
1218
3147
|
name: platformName,
|
|
@@ -1225,26 +3154,59 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1225
3154
|
// Full user agent for more detailed info
|
|
1226
3155
|
[import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1227
3156
|
[import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1228
|
-
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0
|
|
3157
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0"
|
|
1229
3158
|
// Replaced at build time
|
|
1230
3159
|
}
|
|
1231
3160
|
};
|
|
1232
3161
|
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
|
|
1233
3162
|
const logger = new BrowserLogger();
|
|
1234
3163
|
super(config, platform, logger);
|
|
3164
|
+
this.addressTypes = config.addressTypes;
|
|
1235
3165
|
debug.info(DebugCategory.EMBEDDED_PROVIDER, "Browser EmbeddedProvider initialized");
|
|
1236
3166
|
}
|
|
3167
|
+
getEnabledAddressTypes() {
|
|
3168
|
+
return this.addressTypes;
|
|
3169
|
+
}
|
|
1237
3170
|
};
|
|
1238
3171
|
|
|
1239
3172
|
// src/ProviderManager.ts
|
|
3173
|
+
var import_embedded_provider_core2 = require("@phantom/embedded-provider-core");
|
|
1240
3174
|
var import_constants3 = require("@phantom/constants");
|
|
3175
|
+
|
|
3176
|
+
// src/utils/auth-callback.ts
|
|
3177
|
+
function isAuthFailureCallback(searchParams) {
|
|
3178
|
+
if (typeof window === "undefined" && !searchParams)
|
|
3179
|
+
return false;
|
|
3180
|
+
const params = searchParams || new URLSearchParams(window.location.search);
|
|
3181
|
+
const responseType = params.get("response_type");
|
|
3182
|
+
const sessionId = params.get("session_id");
|
|
3183
|
+
return responseType === "failure" && !!sessionId;
|
|
3184
|
+
}
|
|
3185
|
+
function isAuthCallbackUrl(searchParams) {
|
|
3186
|
+
if (typeof window === "undefined" && !searchParams)
|
|
3187
|
+
return false;
|
|
3188
|
+
const params = searchParams || new URLSearchParams(window.location.search);
|
|
3189
|
+
const sessionId = params.get("session_id");
|
|
3190
|
+
return !!(sessionId && (params.has("response_type") || params.has("wallet_id")));
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3193
|
+
// src/utils/deeplink.ts
|
|
3194
|
+
function getDeeplinkToPhantom(ref) {
|
|
3195
|
+
if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
|
|
3196
|
+
throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
|
|
3197
|
+
}
|
|
3198
|
+
const currentUrl = encodeURIComponent(window.location.href);
|
|
3199
|
+
const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
|
|
3200
|
+
return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
|
|
3201
|
+
}
|
|
3202
|
+
|
|
3203
|
+
// src/ProviderManager.ts
|
|
1241
3204
|
var ProviderManager = class {
|
|
1242
3205
|
// Track which providers have forwarding set up
|
|
1243
3206
|
constructor(config) {
|
|
1244
3207
|
this.providers = /* @__PURE__ */ new Map();
|
|
1245
3208
|
this.currentProvider = null;
|
|
1246
3209
|
this.currentProviderKey = null;
|
|
1247
|
-
this.walletId = null;
|
|
1248
3210
|
// Event management for forwarding provider events
|
|
1249
3211
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
1250
3212
|
this.providerForwardingSetup = /* @__PURE__ */ new WeakSet();
|
|
@@ -1280,7 +3242,6 @@ var ProviderManager = class {
|
|
|
1280
3242
|
}
|
|
1281
3243
|
this.currentProvider = this.providers.get(key);
|
|
1282
3244
|
this.currentProviderKey = key;
|
|
1283
|
-
this.walletId = null;
|
|
1284
3245
|
this.ensureProviderEventForwarding();
|
|
1285
3246
|
return this.currentProvider;
|
|
1286
3247
|
}
|
|
@@ -1303,29 +3264,78 @@ var ProviderManager = class {
|
|
|
1303
3264
|
embeddedWalletType
|
|
1304
3265
|
};
|
|
1305
3266
|
}
|
|
3267
|
+
/**
|
|
3268
|
+
* Check if a provider is allowed by the config
|
|
3269
|
+
*/
|
|
3270
|
+
isProviderAllowed(provider) {
|
|
3271
|
+
return this.config.providers.includes(provider);
|
|
3272
|
+
}
|
|
1306
3273
|
/**
|
|
1307
3274
|
* Connect using the current provider
|
|
3275
|
+
* Automatically switches provider based on authOptions.provider
|
|
1308
3276
|
*/
|
|
1309
3277
|
async connect(authOptions) {
|
|
1310
3278
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
|
|
1311
3279
|
currentProviderKey: this.currentProviderKey,
|
|
1312
|
-
authOptions:
|
|
3280
|
+
authOptions: { provider: authOptions.provider }
|
|
1313
3281
|
});
|
|
3282
|
+
if (!this.isProviderAllowed(authOptions.provider)) {
|
|
3283
|
+
const error = `Provider "${authOptions.provider}" is not in the allowed providers list: ${JSON.stringify(this.config.providers)}`;
|
|
3284
|
+
debug.error(DebugCategory.PROVIDER_MANAGER, error);
|
|
3285
|
+
throw new Error(error);
|
|
3286
|
+
}
|
|
3287
|
+
const requestedProvider = authOptions.provider;
|
|
3288
|
+
let targetProviderType = null;
|
|
3289
|
+
if (requestedProvider === "injected") {
|
|
3290
|
+
targetProviderType = "injected";
|
|
3291
|
+
} else if (requestedProvider === "deeplink") {
|
|
3292
|
+
try {
|
|
3293
|
+
const deeplinkUrl = getDeeplinkToPhantom();
|
|
3294
|
+
if (typeof window !== "undefined") {
|
|
3295
|
+
window.location.href = deeplinkUrl;
|
|
3296
|
+
}
|
|
3297
|
+
return {
|
|
3298
|
+
addresses: [],
|
|
3299
|
+
walletId: void 0,
|
|
3300
|
+
authUserId: void 0
|
|
3301
|
+
};
|
|
3302
|
+
} catch (error) {
|
|
3303
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to open deeplink";
|
|
3304
|
+
debug.error(DebugCategory.PROVIDER_MANAGER, "Deeplink error", { error: errorMessage });
|
|
3305
|
+
throw new Error(`Failed to open deeplink: ${errorMessage}`);
|
|
3306
|
+
}
|
|
3307
|
+
} else if (import_embedded_provider_core2.EMBEDDED_PROVIDER_AUTH_TYPES.includes(requestedProvider)) {
|
|
3308
|
+
targetProviderType = "embedded";
|
|
3309
|
+
}
|
|
3310
|
+
if (targetProviderType) {
|
|
3311
|
+
const currentInfo = this.getCurrentProviderInfo();
|
|
3312
|
+
if (currentInfo?.type !== targetProviderType) {
|
|
3313
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-switching provider based on auth options", {
|
|
3314
|
+
from: currentInfo?.type,
|
|
3315
|
+
to: targetProviderType,
|
|
3316
|
+
requestedProvider
|
|
3317
|
+
});
|
|
3318
|
+
const switchOptions = {};
|
|
3319
|
+
if (targetProviderType === "embedded") {
|
|
3320
|
+
switchOptions.embeddedWalletType = currentInfo?.embeddedWalletType || this.config.embeddedWalletType;
|
|
3321
|
+
}
|
|
3322
|
+
this.switchProvider(targetProviderType, switchOptions);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
1314
3325
|
if (!this.currentProvider) {
|
|
1315
3326
|
debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
|
|
1316
3327
|
throw new Error("No provider selected");
|
|
1317
3328
|
}
|
|
1318
3329
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
|
|
1319
3330
|
const result = await this.currentProvider.connect(authOptions);
|
|
1320
|
-
this.walletId = result.walletId || null;
|
|
1321
3331
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
|
|
1322
|
-
|
|
1323
|
-
|
|
3332
|
+
addressCount: result.addresses?.length || 0,
|
|
3333
|
+
provider: authOptions.provider
|
|
1324
3334
|
});
|
|
1325
3335
|
this.saveProviderPreference();
|
|
1326
3336
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
|
|
1327
|
-
|
|
1328
|
-
|
|
3337
|
+
addresses: result.addresses,
|
|
3338
|
+
provider: authOptions.provider
|
|
1329
3339
|
});
|
|
1330
3340
|
return result;
|
|
1331
3341
|
}
|
|
@@ -1336,7 +3346,6 @@ var ProviderManager = class {
|
|
|
1336
3346
|
if (!this.currentProvider)
|
|
1337
3347
|
return;
|
|
1338
3348
|
await this.currentProvider.disconnect();
|
|
1339
|
-
this.walletId = null;
|
|
1340
3349
|
}
|
|
1341
3350
|
/**
|
|
1342
3351
|
* Get addresses from current provider
|
|
@@ -1354,10 +3363,71 @@ var ProviderManager = class {
|
|
|
1354
3363
|
return this.currentProvider?.isConnected() ?? false;
|
|
1355
3364
|
}
|
|
1356
3365
|
/**
|
|
1357
|
-
*
|
|
3366
|
+
* Attempt auto-connect with fallback strategy
|
|
3367
|
+
* Tries embedded provider first if it exists and is allowed, then injected provider if allowed
|
|
3368
|
+
* Returns true if any provider successfully connected
|
|
1358
3369
|
*/
|
|
1359
|
-
|
|
1360
|
-
|
|
3370
|
+
async autoConnect() {
|
|
3371
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Starting auto-connect with fallback strategy");
|
|
3372
|
+
if (isAuthFailureCallback()) {
|
|
3373
|
+
debug.warn(DebugCategory.PROVIDER_MANAGER, "Auth failure detected in URL, skipping autoConnect fallback");
|
|
3374
|
+
return false;
|
|
3375
|
+
}
|
|
3376
|
+
const embeddedWalletType = this.config.embeddedWalletType || "user-wallet";
|
|
3377
|
+
const embeddedKey = this.getProviderKey("embedded", embeddedWalletType);
|
|
3378
|
+
const embeddedAllowed = this.config.providers.some((p) => p !== "injected");
|
|
3379
|
+
if (embeddedAllowed && this.providers.has(embeddedKey)) {
|
|
3380
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Trying auto-connect with existing embedded provider");
|
|
3381
|
+
const embeddedProvider = this.providers.get(embeddedKey);
|
|
3382
|
+
try {
|
|
3383
|
+
const previousProvider = this.currentProvider;
|
|
3384
|
+
const previousKey = this.currentProviderKey;
|
|
3385
|
+
this.currentProvider = embeddedProvider;
|
|
3386
|
+
this.currentProviderKey = embeddedKey;
|
|
3387
|
+
this.ensureProviderEventForwarding();
|
|
3388
|
+
await embeddedProvider.autoConnect();
|
|
3389
|
+
if (embeddedProvider.isConnected()) {
|
|
3390
|
+
debug.info(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect successful");
|
|
3391
|
+
this.saveProviderPreference();
|
|
3392
|
+
return true;
|
|
3393
|
+
} else {
|
|
3394
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded provider did not connect, restoring previous provider");
|
|
3395
|
+
this.currentProvider = previousProvider;
|
|
3396
|
+
this.currentProviderKey = previousKey;
|
|
3397
|
+
}
|
|
3398
|
+
} catch (error) {
|
|
3399
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect failed", {
|
|
3400
|
+
error: error.message
|
|
3401
|
+
});
|
|
3402
|
+
if (isAuthCallbackUrl()) {
|
|
3403
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "In auth callback URL, not attempting injected fallback");
|
|
3404
|
+
return false;
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
const injectedAllowed = this.config.providers.includes("injected");
|
|
3409
|
+
const injectedKey = this.getProviderKey("injected");
|
|
3410
|
+
if (injectedAllowed && this.providers.has(injectedKey)) {
|
|
3411
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Trying auto-connect with existing injected provider");
|
|
3412
|
+
const injectedProvider = this.providers.get(injectedKey);
|
|
3413
|
+
try {
|
|
3414
|
+
this.currentProvider = injectedProvider;
|
|
3415
|
+
this.currentProviderKey = injectedKey;
|
|
3416
|
+
this.ensureProviderEventForwarding();
|
|
3417
|
+
await injectedProvider.autoConnect();
|
|
3418
|
+
if (injectedProvider.isConnected()) {
|
|
3419
|
+
debug.info(DebugCategory.PROVIDER_MANAGER, "Injected auto-connect successful");
|
|
3420
|
+
this.saveProviderPreference();
|
|
3421
|
+
return true;
|
|
3422
|
+
}
|
|
3423
|
+
} catch (error) {
|
|
3424
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Injected auto-connect failed", {
|
|
3425
|
+
error: error.message
|
|
3426
|
+
});
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-connect failed for all allowed providers");
|
|
3430
|
+
return false;
|
|
1361
3431
|
}
|
|
1362
3432
|
/**
|
|
1363
3433
|
* Add event listener - stores callback and ensures current provider forwards events to ProviderManager
|
|
@@ -1426,7 +3496,8 @@ var ProviderManager = class {
|
|
|
1426
3496
|
"connect",
|
|
1427
3497
|
"connect_error",
|
|
1428
3498
|
"disconnect",
|
|
1429
|
-
"error"
|
|
3499
|
+
"error",
|
|
3500
|
+
"spending_limit_reached"
|
|
1430
3501
|
];
|
|
1431
3502
|
for (const event of eventsToForward) {
|
|
1432
3503
|
const forwardingCallback = (data) => {
|
|
@@ -1440,12 +3511,33 @@ var ProviderManager = class {
|
|
|
1440
3511
|
}
|
|
1441
3512
|
/**
|
|
1442
3513
|
* Set default provider based on initial config
|
|
3514
|
+
* Creates providers based on the allowed providers array
|
|
1443
3515
|
*/
|
|
1444
3516
|
setDefaultProvider() {
|
|
1445
|
-
const defaultType = this.config.providerType || "embedded";
|
|
1446
3517
|
const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
|
|
1447
|
-
this.
|
|
1448
|
-
this.
|
|
3518
|
+
const hasInjected = this.config.providers.includes("injected");
|
|
3519
|
+
const hasEmbedded = this.config.providers.some((p) => p !== "injected" && p !== "deeplink");
|
|
3520
|
+
if (hasInjected) {
|
|
3521
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Creating injected provider (allowed by providers array)");
|
|
3522
|
+
this.createProvider("injected");
|
|
3523
|
+
}
|
|
3524
|
+
if (hasEmbedded) {
|
|
3525
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Creating embedded provider (allowed by providers array)");
|
|
3526
|
+
this.createProvider("embedded", defaultEmbeddedType);
|
|
3527
|
+
}
|
|
3528
|
+
let defaultType;
|
|
3529
|
+
if (hasEmbedded && this.providers.has(`embedded-${defaultEmbeddedType}`)) {
|
|
3530
|
+
defaultType = "embedded";
|
|
3531
|
+
} else if (hasInjected && this.providers.has("injected")) {
|
|
3532
|
+
defaultType = "injected";
|
|
3533
|
+
} else {
|
|
3534
|
+
throw new Error("No valid providers could be created from the providers array");
|
|
3535
|
+
}
|
|
3536
|
+
const switchOptions = {};
|
|
3537
|
+
if (defaultType === "embedded") {
|
|
3538
|
+
switchOptions.embeddedWalletType = defaultEmbeddedType;
|
|
3539
|
+
}
|
|
3540
|
+
this.switchProvider(defaultType, switchOptions);
|
|
1449
3541
|
}
|
|
1450
3542
|
/**
|
|
1451
3543
|
* Create a provider instance
|
|
@@ -1505,66 +3597,48 @@ var ProviderManager = class {
|
|
|
1505
3597
|
console.error("Failed to save provider preference:", error);
|
|
1506
3598
|
}
|
|
1507
3599
|
}
|
|
1508
|
-
/**
|
|
1509
|
-
* Restore provider preference from localStorage
|
|
1510
|
-
*/
|
|
1511
|
-
/*
|
|
1512
|
-
private restoreProviderPreference(): void {
|
|
1513
|
-
try {
|
|
1514
|
-
const saved = localStorage.getItem("phantom-provider-preference");
|
|
1515
|
-
if (saved) {
|
|
1516
|
-
const preference: ProviderPreference = JSON.parse(saved);
|
|
1517
|
-
this.switchProvider(preference.type, {
|
|
1518
|
-
embeddedWalletType: preference.embeddedWalletType,
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
} catch (error) {
|
|
1522
|
-
// Ignore localStorage errors - just use default provider
|
|
1523
|
-
console.error("Failed to restore provider preference:", error);
|
|
1524
|
-
}
|
|
1525
|
-
}*/
|
|
1526
3600
|
};
|
|
1527
3601
|
|
|
1528
|
-
// src/waitForPhantomExtension.ts
|
|
1529
|
-
var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
|
|
1530
|
-
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1531
|
-
return new Promise((resolve) => {
|
|
1532
|
-
const startTime = Date.now();
|
|
1533
|
-
const checkInterval = 100;
|
|
1534
|
-
const checkForExtension = () => {
|
|
1535
|
-
try {
|
|
1536
|
-
if ((0, import_browser_injected_sdk2.isPhantomExtensionInstalled)()) {
|
|
1537
|
-
resolve(true);
|
|
1538
|
-
return;
|
|
1539
|
-
}
|
|
1540
|
-
} catch (error) {
|
|
1541
|
-
}
|
|
1542
|
-
const elapsed = Date.now() - startTime;
|
|
1543
|
-
if (elapsed >= timeoutMs) {
|
|
1544
|
-
resolve(false);
|
|
1545
|
-
return;
|
|
1546
|
-
}
|
|
1547
|
-
setTimeout(checkForExtension, checkInterval);
|
|
1548
|
-
};
|
|
1549
|
-
checkForExtension();
|
|
1550
|
-
});
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
3602
|
// src/BrowserSDK.ts
|
|
3603
|
+
var import_embedded_provider_core3 = require("@phantom/embedded-provider-core");
|
|
1554
3604
|
var import_constants4 = require("@phantom/constants");
|
|
3605
|
+
var BROWSER_SDK_PROVIDER_TYPES = [
|
|
3606
|
+
...import_embedded_provider_core3.EMBEDDED_PROVIDER_AUTH_TYPES,
|
|
3607
|
+
"injected",
|
|
3608
|
+
"deeplink"
|
|
3609
|
+
];
|
|
1555
3610
|
var BrowserSDK = class {
|
|
1556
3611
|
constructor(config) {
|
|
3612
|
+
this.walletRegistry = getWalletRegistry();
|
|
3613
|
+
this.isLoading = true;
|
|
1557
3614
|
debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
|
|
1558
|
-
|
|
3615
|
+
providers: config.providers,
|
|
1559
3616
|
embeddedWalletType: config.embeddedWalletType,
|
|
1560
3617
|
addressTypes: config.addressTypes
|
|
1561
3618
|
});
|
|
1562
|
-
if (!
|
|
1563
|
-
debug.error(DebugCategory.BROWSER_SDK, "Invalid
|
|
1564
|
-
throw new Error(
|
|
3619
|
+
if (!Array.isArray(config.providers) || config.providers.length === 0) {
|
|
3620
|
+
debug.error(DebugCategory.BROWSER_SDK, "Invalid providers array", { providers: config.providers });
|
|
3621
|
+
throw new Error("providers must be a non-empty array of AuthProviderType");
|
|
3622
|
+
}
|
|
3623
|
+
const invalidProviders = config.providers.filter((p) => !BROWSER_SDK_PROVIDER_TYPES.includes(p));
|
|
3624
|
+
if (invalidProviders.length > 0) {
|
|
3625
|
+
debug.error(DebugCategory.BROWSER_SDK, "Invalid provider types", {
|
|
3626
|
+
invalidProviders,
|
|
3627
|
+
validProviders: BROWSER_SDK_PROVIDER_TYPES
|
|
3628
|
+
});
|
|
3629
|
+
throw new Error(
|
|
3630
|
+
`Invalid provider type(s): ${invalidProviders.join(", ")}. Valid providers are: ${BROWSER_SDK_PROVIDER_TYPES.join(", ")}`
|
|
3631
|
+
);
|
|
3632
|
+
}
|
|
3633
|
+
const hasEmbeddedProviders = config.providers.some((p) => p !== "injected");
|
|
3634
|
+
if (hasEmbeddedProviders && !config.appId) {
|
|
3635
|
+
debug.error(DebugCategory.BROWSER_SDK, "appId required for embedded providers", {
|
|
3636
|
+
providers: config.providers
|
|
3637
|
+
});
|
|
3638
|
+
throw new Error("appId is required when using embedded providers (google, apple, phantom, etc.)");
|
|
1565
3639
|
}
|
|
1566
3640
|
const embeddedWalletType = config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE;
|
|
1567
|
-
if (
|
|
3641
|
+
if (!["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
|
|
1568
3642
|
debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
|
|
1569
3643
|
embeddedWalletType: config.embeddedWalletType
|
|
1570
3644
|
});
|
|
@@ -1572,7 +3646,14 @@ var BrowserSDK = class {
|
|
|
1572
3646
|
`Invalid embeddedWalletType: ${config.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
|
|
1573
3647
|
);
|
|
1574
3648
|
}
|
|
3649
|
+
this.config = config;
|
|
1575
3650
|
this.providerManager = new ProviderManager(config);
|
|
3651
|
+
void this.discoverWallets();
|
|
3652
|
+
}
|
|
3653
|
+
discoverWallets() {
|
|
3654
|
+
return this.walletRegistry.discover(this.config.addressTypes).finally(() => {
|
|
3655
|
+
this.isLoading = false;
|
|
3656
|
+
});
|
|
1576
3657
|
}
|
|
1577
3658
|
// ===== CHAIN API =====
|
|
1578
3659
|
/**
|
|
@@ -1605,7 +3686,6 @@ var BrowserSDK = class {
|
|
|
1605
3686
|
const result = await this.providerManager.connect(options);
|
|
1606
3687
|
debug.info(DebugCategory.BROWSER_SDK, "Connection successful", {
|
|
1607
3688
|
addressCount: result.addresses.length,
|
|
1608
|
-
walletId: result.walletId,
|
|
1609
3689
|
status: result.status
|
|
1610
3690
|
});
|
|
1611
3691
|
return result;
|
|
@@ -1627,22 +3707,6 @@ var BrowserSDK = class {
|
|
|
1627
3707
|
throw error;
|
|
1628
3708
|
}
|
|
1629
3709
|
}
|
|
1630
|
-
/**
|
|
1631
|
-
* Switch between provider types (injected vs embedded)
|
|
1632
|
-
*/
|
|
1633
|
-
async switchProvider(type, options) {
|
|
1634
|
-
debug.info(DebugCategory.BROWSER_SDK, "Switching provider", { type, options });
|
|
1635
|
-
try {
|
|
1636
|
-
await this.providerManager.switchProvider(type, options);
|
|
1637
|
-
debug.info(DebugCategory.BROWSER_SDK, "Provider switch successful", { type });
|
|
1638
|
-
} catch (error) {
|
|
1639
|
-
debug.error(DebugCategory.BROWSER_SDK, "Provider switch failed", {
|
|
1640
|
-
type,
|
|
1641
|
-
error: error.message
|
|
1642
|
-
});
|
|
1643
|
-
throw error;
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
3710
|
// ===== STATE QUERIES =====
|
|
1647
3711
|
/**
|
|
1648
3712
|
* Check if the SDK is connected to a wallet
|
|
@@ -1663,18 +3727,19 @@ var BrowserSDK = class {
|
|
|
1663
3727
|
return this.providerManager.getCurrentProviderInfo();
|
|
1664
3728
|
}
|
|
1665
3729
|
/**
|
|
1666
|
-
* Get
|
|
3730
|
+
* Get enabled address types for the current provider
|
|
3731
|
+
* - For embedded provider: returns config.addressTypes
|
|
3732
|
+
* - For Phantom injected: returns config.addressTypes
|
|
3733
|
+
* - For discovered wallets: returns the wallet's addressTypes from registry
|
|
1667
3734
|
*/
|
|
1668
|
-
|
|
1669
|
-
|
|
3735
|
+
getEnabledAddressTypes() {
|
|
3736
|
+
const currentProvider = this.providerManager.getCurrentProvider();
|
|
3737
|
+
if (!currentProvider) {
|
|
3738
|
+
return [];
|
|
3739
|
+
}
|
|
3740
|
+
return currentProvider.getEnabledAddressTypes();
|
|
1670
3741
|
}
|
|
1671
3742
|
// ===== UTILITY METHODS =====
|
|
1672
|
-
/**
|
|
1673
|
-
* Check if Phantom extension is installed
|
|
1674
|
-
*/
|
|
1675
|
-
static async isPhantomInstalled(timeoutMs) {
|
|
1676
|
-
return waitForPhantomExtension(timeoutMs);
|
|
1677
|
-
}
|
|
1678
3743
|
/**
|
|
1679
3744
|
* Add event listener for provider events (connect, connect_start, connect_error, disconnect, error)
|
|
1680
3745
|
* Works with both embedded and injected providers
|
|
@@ -1694,53 +3759,34 @@ var BrowserSDK = class {
|
|
|
1694
3759
|
/**
|
|
1695
3760
|
* Attempt auto-connection using existing session
|
|
1696
3761
|
* Should be called after setting up event listeners
|
|
1697
|
-
*
|
|
3762
|
+
* Tries embedded provider first, then injected provider as fallback
|
|
1698
3763
|
*/
|
|
1699
3764
|
async autoConnect() {
|
|
1700
|
-
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
|
|
1701
|
-
const
|
|
1702
|
-
if (
|
|
1703
|
-
|
|
1704
|
-
} else {
|
|
1705
|
-
debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
|
|
3765
|
+
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
|
|
3766
|
+
const result = await this.providerManager.autoConnect();
|
|
3767
|
+
if (result) {
|
|
3768
|
+
debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
|
|
1706
3769
|
providerType: this.getCurrentProviderInfo()?.type
|
|
1707
3770
|
});
|
|
3771
|
+
} else {
|
|
3772
|
+
debug.log(DebugCategory.BROWSER_SDK, "Auto-connect failed for all providers");
|
|
1708
3773
|
}
|
|
1709
3774
|
}
|
|
1710
|
-
/**
|
|
1711
|
-
* Debug configuration methods
|
|
1712
|
-
* These allow dynamic debug configuration without SDK reinstantiation
|
|
1713
|
-
*/
|
|
1714
|
-
/**
|
|
1715
|
-
* Enable debug logging
|
|
1716
|
-
*/
|
|
1717
3775
|
enableDebug() {
|
|
1718
3776
|
debug.enable();
|
|
1719
3777
|
debug.info(DebugCategory.BROWSER_SDK, "Debug logging enabled");
|
|
1720
3778
|
}
|
|
1721
|
-
/**
|
|
1722
|
-
* Disable debug logging
|
|
1723
|
-
*/
|
|
1724
3779
|
disableDebug() {
|
|
1725
3780
|
debug.disable();
|
|
1726
3781
|
}
|
|
1727
|
-
/**
|
|
1728
|
-
* Set debug level
|
|
1729
|
-
*/
|
|
1730
3782
|
setDebugLevel(level) {
|
|
1731
3783
|
debug.setLevel(level);
|
|
1732
3784
|
debug.info(DebugCategory.BROWSER_SDK, "Debug level updated", { level });
|
|
1733
3785
|
}
|
|
1734
|
-
/**
|
|
1735
|
-
* Set debug callback function
|
|
1736
|
-
*/
|
|
1737
3786
|
setDebugCallback(callback) {
|
|
1738
3787
|
debug.setCallback(callback);
|
|
1739
3788
|
debug.info(DebugCategory.BROWSER_SDK, "Debug callback updated");
|
|
1740
3789
|
}
|
|
1741
|
-
/**
|
|
1742
|
-
* Configure debug settings all at once
|
|
1743
|
-
*/
|
|
1744
3790
|
configureDebug(config) {
|
|
1745
3791
|
if (config.enabled !== void 0) {
|
|
1746
3792
|
if (config.enabled) {
|
|
@@ -1846,18 +3892,49 @@ var BrowserSDK = class {
|
|
|
1846
3892
|
throw error;
|
|
1847
3893
|
}
|
|
1848
3894
|
}
|
|
3895
|
+
getDiscoveredWallets() {
|
|
3896
|
+
debug.log(DebugCategory.BROWSER_SDK, "Getting discovered wallets");
|
|
3897
|
+
try {
|
|
3898
|
+
const allWallets = this.walletRegistry.getByAddressTypes(this.config.addressTypes);
|
|
3899
|
+
debug.log(DebugCategory.BROWSER_SDK, "Retrieved discovered wallets", {
|
|
3900
|
+
count: allWallets.length,
|
|
3901
|
+
walletIds: allWallets.map((w) => w.id)
|
|
3902
|
+
});
|
|
3903
|
+
return allWallets;
|
|
3904
|
+
} catch (error) {
|
|
3905
|
+
debug.error(DebugCategory.BROWSER_SDK, "Failed to get discovered wallets", {
|
|
3906
|
+
error: error.message
|
|
3907
|
+
});
|
|
3908
|
+
return [];
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
1849
3911
|
};
|
|
1850
3912
|
|
|
1851
|
-
// src/
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
3913
|
+
// src/waitForPhantomExtension.ts
|
|
3914
|
+
var import_browser_injected_sdk5 = require("@phantom/browser-injected-sdk");
|
|
3915
|
+
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
3916
|
+
return new Promise((resolve) => {
|
|
3917
|
+
const startTime = Date.now();
|
|
3918
|
+
const checkInterval = 100;
|
|
3919
|
+
const checkForExtension = () => {
|
|
3920
|
+
try {
|
|
3921
|
+
if ((0, import_browser_injected_sdk5.isPhantomExtensionInstalled)()) {
|
|
3922
|
+
resolve(true);
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
} catch (error) {
|
|
3926
|
+
}
|
|
3927
|
+
const elapsed = Date.now() - startTime;
|
|
3928
|
+
if (elapsed >= timeoutMs) {
|
|
3929
|
+
resolve(false);
|
|
3930
|
+
return;
|
|
3931
|
+
}
|
|
3932
|
+
setTimeout(checkForExtension, checkInterval);
|
|
3933
|
+
};
|
|
3934
|
+
checkForExtension();
|
|
3935
|
+
});
|
|
1859
3936
|
}
|
|
1860
3937
|
|
|
1861
3938
|
// src/index.ts
|
|
1862
3939
|
var import_constants5 = require("@phantom/constants");
|
|
1863
|
-
var
|
|
3940
|
+
var import_client4 = require("@phantom/client");
|