@phantom/browser-sdk 1.0.0-beta.22 → 1.0.0-beta.24
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 +78 -0
- package/dist/index.d.ts +31 -27
- package/dist/index.js +2165 -457
- package/dist/index.mjs +2156 -460
- package/package.json +15 -10
package/dist/index.mjs
CHANGED
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
import { AddressType } from "@phantom/client";
|
|
3
3
|
|
|
4
4
|
// src/providers/injected/index.ts
|
|
5
|
-
import { AddressType as
|
|
6
|
-
import { createPhantom, createExtensionPlugin } from "@phantom/browser-injected-sdk";
|
|
7
|
-
import { createSolanaPlugin } from "@phantom/browser-injected-sdk/solana";
|
|
8
|
-
import { createEthereumPlugin } from "@phantom/browser-injected-sdk/ethereum";
|
|
9
|
-
import {
|
|
10
|
-
createAutoConfirmPlugin
|
|
11
|
-
} from "@phantom/browser-injected-sdk/auto-confirm";
|
|
5
|
+
import { AddressType as AddressType2 } from "@phantom/client";
|
|
12
6
|
|
|
13
7
|
// src/debug.ts
|
|
14
8
|
var DebugLevel = /* @__PURE__ */ ((DebugLevel2) => {
|
|
@@ -27,111 +21,1435 @@ var Debug = class {
|
|
|
27
21
|
if (!Debug.instance) {
|
|
28
22
|
Debug.instance = new Debug();
|
|
29
23
|
}
|
|
30
|
-
return Debug.instance;
|
|
24
|
+
return Debug.instance;
|
|
25
|
+
}
|
|
26
|
+
setCallback(callback) {
|
|
27
|
+
this.callback = callback;
|
|
28
|
+
}
|
|
29
|
+
setLevel(level) {
|
|
30
|
+
this.level = level;
|
|
31
|
+
}
|
|
32
|
+
enable() {
|
|
33
|
+
this.enabled = true;
|
|
34
|
+
}
|
|
35
|
+
disable() {
|
|
36
|
+
this.enabled = false;
|
|
37
|
+
}
|
|
38
|
+
writeLog(level, category, message, data) {
|
|
39
|
+
if (!this.enabled || level > this.level) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const debugMessage = {
|
|
43
|
+
timestamp: Date.now(),
|
|
44
|
+
level,
|
|
45
|
+
category,
|
|
46
|
+
message,
|
|
47
|
+
data
|
|
48
|
+
};
|
|
49
|
+
if (this.callback) {
|
|
50
|
+
this.callback(debugMessage);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
error(category, message, data) {
|
|
54
|
+
this.writeLog(0 /* ERROR */, category, message, data);
|
|
55
|
+
}
|
|
56
|
+
warn(category, message, data) {
|
|
57
|
+
this.writeLog(1 /* WARN */, category, message, data);
|
|
58
|
+
}
|
|
59
|
+
info(category, message, data) {
|
|
60
|
+
this.writeLog(2 /* INFO */, category, message, data);
|
|
61
|
+
}
|
|
62
|
+
debug(category, message, data) {
|
|
63
|
+
this.writeLog(3 /* DEBUG */, category, message, data);
|
|
64
|
+
}
|
|
65
|
+
log(category, message, data) {
|
|
66
|
+
this.writeLog(3 /* DEBUG */, category, message, data);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var debug = Debug.getInstance();
|
|
70
|
+
var DebugCategory = {
|
|
71
|
+
BROWSER_SDK: "BrowserSDK",
|
|
72
|
+
PROVIDER_MANAGER: "ProviderManager",
|
|
73
|
+
EMBEDDED_PROVIDER: "EmbeddedProvider",
|
|
74
|
+
INJECTED_PROVIDER: "InjectedProvider",
|
|
75
|
+
PHANTOM_CONNECT_AUTH: "PhantomConnectAuth",
|
|
76
|
+
JWT_AUTH: "JWTAuth",
|
|
77
|
+
STORAGE: "Storage",
|
|
78
|
+
SESSION: "Session"
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/wallets/discovery.ts
|
|
82
|
+
import { AddressType as ClientAddressType } from "@phantom/client";
|
|
83
|
+
import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
|
|
84
|
+
import { createPhantom, createExtensionPlugin } from "@phantom/browser-injected-sdk";
|
|
85
|
+
import { createSolanaPlugin } from "@phantom/browser-injected-sdk/solana";
|
|
86
|
+
import { createEthereumPlugin } from "@phantom/browser-injected-sdk/ethereum";
|
|
87
|
+
import { createAutoConfirmPlugin } from "@phantom/browser-injected-sdk/auto-confirm";
|
|
88
|
+
function generateWalletIdFromEIP6963(info) {
|
|
89
|
+
if (info.rdns) {
|
|
90
|
+
return info.rdns.split(".").reverse().join("-");
|
|
91
|
+
}
|
|
92
|
+
return info.name.toLowerCase().replace(/\s+/g, "-");
|
|
93
|
+
}
|
|
94
|
+
function generateWalletIdFromName(name) {
|
|
95
|
+
return name.toLowerCase().replace(/\s+/g, "-");
|
|
96
|
+
}
|
|
97
|
+
function processEIP6963Providers(providers) {
|
|
98
|
+
const wallets = [];
|
|
99
|
+
debug.log(DebugCategory.BROWSER_SDK, "Processing EIP-6963 providers", {
|
|
100
|
+
providerCount: providers.size,
|
|
101
|
+
providerNames: Array.from(providers.values()).map((d) => d.info.name)
|
|
102
|
+
});
|
|
103
|
+
for (const [, detail] of providers) {
|
|
104
|
+
const { info, provider } = detail;
|
|
105
|
+
const isPhantom = info.name.toLowerCase().includes("phantom") || info.rdns && (info.rdns.toLowerCase().includes("phantom") || info.rdns.toLowerCase() === "app.phantom");
|
|
106
|
+
if (isPhantom) {
|
|
107
|
+
debug.log(DebugCategory.BROWSER_SDK, "Skipping Phantom from EIP-6963", { name: info.name, rdns: info.rdns });
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const walletId = generateWalletIdFromEIP6963(info);
|
|
111
|
+
debug.log(DebugCategory.BROWSER_SDK, "Discovered EIP-6963 wallet", {
|
|
112
|
+
walletId,
|
|
113
|
+
walletName: info.name,
|
|
114
|
+
rdns: info.rdns
|
|
115
|
+
});
|
|
116
|
+
wallets.push({
|
|
117
|
+
id: walletId,
|
|
118
|
+
name: info.name,
|
|
119
|
+
icon: info.icon,
|
|
120
|
+
addressTypes: [ClientAddressType.ethereum],
|
|
121
|
+
providers: {
|
|
122
|
+
// EIP-6963 provider implements EIP-1193 interface (IEthereumChain)
|
|
123
|
+
ethereum: provider
|
|
124
|
+
},
|
|
125
|
+
rdns: info.rdns
|
|
126
|
+
// Store rdns for potential future matching
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
debug.log(DebugCategory.BROWSER_SDK, "EIP-6963 discovery completed", {
|
|
130
|
+
discoveredCount: wallets.length,
|
|
131
|
+
walletIds: wallets.map((w) => w.id)
|
|
132
|
+
});
|
|
133
|
+
return wallets;
|
|
134
|
+
}
|
|
135
|
+
function discoverEthereumWallets() {
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
const discoveredProviders = /* @__PURE__ */ new Map();
|
|
138
|
+
if (typeof window === "undefined") {
|
|
139
|
+
resolve([]);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const handleAnnounce = (event) => {
|
|
143
|
+
const detail = event.detail;
|
|
144
|
+
if (detail?.info && detail?.provider) {
|
|
145
|
+
discoveredProviders.set(detail.info.uuid, detail);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
window.addEventListener("eip6963:announceProvider", handleAnnounce);
|
|
149
|
+
window.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
150
|
+
const processProviders = () => {
|
|
151
|
+
const wallets = processEIP6963Providers(discoveredProviders);
|
|
152
|
+
window.removeEventListener("eip6963:announceProvider", handleAnnounce);
|
|
153
|
+
resolve(wallets);
|
|
154
|
+
};
|
|
155
|
+
setTimeout(processProviders, 400);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async function discoverSolanaWallets() {
|
|
159
|
+
const wallets = [];
|
|
160
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
161
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard discovery skipped (not in browser environment)");
|
|
162
|
+
return wallets;
|
|
163
|
+
}
|
|
164
|
+
const registeredWalletsSet = /* @__PURE__ */ new Set();
|
|
165
|
+
let cachedWalletsArray;
|
|
166
|
+
function addRegisteredWallet(wallet) {
|
|
167
|
+
cachedWalletsArray = void 0;
|
|
168
|
+
registeredWalletsSet.add(wallet);
|
|
169
|
+
const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
|
|
170
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet registered", {
|
|
171
|
+
name: wallet.name,
|
|
172
|
+
chains: wallet.chains,
|
|
173
|
+
featureKeys,
|
|
174
|
+
totalWallets: registeredWalletsSet.size
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function removeRegisteredWallet(wallet) {
|
|
178
|
+
cachedWalletsArray = void 0;
|
|
179
|
+
registeredWalletsSet.delete(wallet);
|
|
180
|
+
}
|
|
181
|
+
function getRegisteredWallets() {
|
|
182
|
+
if (!cachedWalletsArray) {
|
|
183
|
+
cachedWalletsArray = [...registeredWalletsSet];
|
|
184
|
+
}
|
|
185
|
+
return cachedWalletsArray;
|
|
186
|
+
}
|
|
187
|
+
function register(...wallets2) {
|
|
188
|
+
wallets2 = wallets2.filter((wallet) => !registeredWalletsSet.has(wallet));
|
|
189
|
+
if (!wallets2.length) {
|
|
190
|
+
return () => {
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
wallets2.forEach((wallet) => addRegisteredWallet(wallet));
|
|
194
|
+
return function unregister() {
|
|
195
|
+
wallets2.forEach((wallet) => removeRegisteredWallet(wallet));
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
const registerAPI = Object.freeze({ register });
|
|
199
|
+
const handleRegisterWalletEvent = (event) => {
|
|
200
|
+
const callback = event.detail;
|
|
201
|
+
if (typeof callback === "function") {
|
|
202
|
+
try {
|
|
203
|
+
callback(registerAPI);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Error calling wallet registration callback", { error });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
try {
|
|
210
|
+
window.addEventListener("wallet-standard:register-wallet", handleRegisterWalletEvent);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Could not add register-wallet event listener", { error });
|
|
213
|
+
}
|
|
214
|
+
class AppReadyEvent extends Event {
|
|
215
|
+
constructor(api) {
|
|
216
|
+
super("wallet-standard:app-ready", {
|
|
217
|
+
bubbles: false,
|
|
218
|
+
cancelable: false,
|
|
219
|
+
composed: false
|
|
220
|
+
});
|
|
221
|
+
this.detail = api;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
window.dispatchEvent(new AppReadyEvent(registerAPI));
|
|
226
|
+
debug.log(DebugCategory.BROWSER_SDK, "Dispatched wallet-standard:app-ready event");
|
|
227
|
+
} catch (error) {
|
|
228
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Could not dispatch app-ready event", { error });
|
|
229
|
+
}
|
|
230
|
+
const walletsAPI = {
|
|
231
|
+
getWallets: () => {
|
|
232
|
+
return {
|
|
233
|
+
get: getRegisteredWallets,
|
|
234
|
+
on: (_event, _listener) => {
|
|
235
|
+
return () => {
|
|
236
|
+
};
|
|
237
|
+
},
|
|
238
|
+
register
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
if (!navigator.wallets) {
|
|
243
|
+
navigator.wallets = walletsAPI;
|
|
244
|
+
}
|
|
245
|
+
debug.log(DebugCategory.BROWSER_SDK, "Initialized Wallet Standard registry");
|
|
246
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
247
|
+
const existingWalletsAPI = navigator.wallets || window.wallets;
|
|
248
|
+
if (!existingWalletsAPI || typeof existingWalletsAPI.getWallets !== "function") {
|
|
249
|
+
const logData = {
|
|
250
|
+
hasNavigator: !!navigator,
|
|
251
|
+
hasWindow: typeof window !== "undefined",
|
|
252
|
+
note: "Wallet Standard API not properly initialized"
|
|
253
|
+
};
|
|
254
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard API not available", logData);
|
|
255
|
+
return wallets;
|
|
256
|
+
}
|
|
257
|
+
const walletsGetter = existingWalletsAPI.getWallets();
|
|
258
|
+
const getWalletsFn = () => Promise.resolve([...walletsGetter.get()]);
|
|
259
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard API detected, starting discovery");
|
|
260
|
+
try {
|
|
261
|
+
let registeredWallets = [];
|
|
262
|
+
let attempts = 0;
|
|
263
|
+
const maxAttempts = 5;
|
|
264
|
+
const initialDelay = 100;
|
|
265
|
+
const eip6963Timeout = 400;
|
|
266
|
+
await new Promise((resolve) => setTimeout(resolve, initialDelay));
|
|
267
|
+
while (attempts < maxAttempts) {
|
|
268
|
+
registeredWallets = await getWalletsFn();
|
|
269
|
+
const logData = {
|
|
270
|
+
attempt: attempts + 1,
|
|
271
|
+
walletCount: registeredWallets.length,
|
|
272
|
+
walletNames: registeredWallets.map((w) => w.name),
|
|
273
|
+
chains: registeredWallets.flatMap((w) => w.chains)
|
|
274
|
+
};
|
|
275
|
+
debug.log(DebugCategory.BROWSER_SDK, `Wallet Standard getWallets attempt ${attempts + 1}`, logData);
|
|
276
|
+
if (registeredWallets.length > 0 || attempts === maxAttempts - 1) {
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
await new Promise((resolve) => setTimeout(resolve, initialDelay));
|
|
280
|
+
attempts++;
|
|
281
|
+
}
|
|
282
|
+
const totalWaitTime = initialDelay + attempts * initialDelay;
|
|
283
|
+
if (totalWaitTime < eip6963Timeout) {
|
|
284
|
+
const remainingWait = eip6963Timeout - totalWaitTime;
|
|
285
|
+
await new Promise((resolve) => setTimeout(resolve, remainingWait));
|
|
286
|
+
registeredWallets = await getWalletsFn();
|
|
287
|
+
}
|
|
288
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard getWallets final result", {
|
|
289
|
+
walletCount: registeredWallets.length,
|
|
290
|
+
walletNames: registeredWallets.map((w) => w.name),
|
|
291
|
+
attempts: attempts + 1
|
|
292
|
+
});
|
|
293
|
+
for (const wallet of registeredWallets) {
|
|
294
|
+
const supportsSolana = wallet.chains.some((chain) => {
|
|
295
|
+
const chainLower = chain.toLowerCase();
|
|
296
|
+
return chainLower.startsWith("solana:") || chainLower === "solana";
|
|
297
|
+
}) || wallet.features && typeof wallet.features === "object" && Object.keys(wallet.features).some((featureKey) => {
|
|
298
|
+
const featureLower = featureKey.toLowerCase();
|
|
299
|
+
return featureLower.includes("solana") || featureLower.includes("standard:connect") || featureLower.includes("standard:signTransaction");
|
|
300
|
+
});
|
|
301
|
+
if (!supportsSolana) {
|
|
302
|
+
const featureKeys = wallet.features ? Object.keys(wallet.features) : [];
|
|
303
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet does not support Solana", {
|
|
304
|
+
walletName: wallet.name,
|
|
305
|
+
chains: wallet.chains,
|
|
306
|
+
featureKeys
|
|
307
|
+
});
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (wallet.name.toLowerCase().includes("phantom")) {
|
|
311
|
+
debug.log(DebugCategory.BROWSER_SDK, "Skipping Phantom from Wallet Standard (handled separately)");
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
const walletId = generateWalletIdFromName(wallet.name);
|
|
315
|
+
const safeFeatures = wallet.features ? Object.keys(wallet.features) : [];
|
|
316
|
+
debug.log(DebugCategory.BROWSER_SDK, "Discovered Wallet Standard Solana wallet", {
|
|
317
|
+
walletId,
|
|
318
|
+
walletName: wallet.name,
|
|
319
|
+
chains: wallet.chains,
|
|
320
|
+
featureKeys: safeFeatures,
|
|
321
|
+
icon: wallet.icon,
|
|
322
|
+
version: wallet.version,
|
|
323
|
+
accountCount: wallet.accounts?.length || 0
|
|
324
|
+
});
|
|
325
|
+
wallets.push({
|
|
326
|
+
id: walletId,
|
|
327
|
+
name: wallet.name,
|
|
328
|
+
icon: wallet.icon,
|
|
329
|
+
addressTypes: [ClientAddressType.solana],
|
|
330
|
+
providers: {
|
|
331
|
+
// Cast to ISolanaChain - Wallet Standard wallets have compatible methods
|
|
332
|
+
// The InjectedWalletSolanaChain wrapper will handle the actual method calls
|
|
333
|
+
solana: wallet
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Wallet Standard API error", {
|
|
339
|
+
error: error instanceof Error ? error.message : String(error),
|
|
340
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const finalLogData = {
|
|
344
|
+
discoveredCount: wallets.length,
|
|
345
|
+
walletIds: wallets.map((w) => w.id),
|
|
346
|
+
walletNames: wallets.map((w) => w.name)
|
|
347
|
+
};
|
|
348
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wallet Standard Solana discovery completed", finalLogData);
|
|
349
|
+
return wallets;
|
|
350
|
+
}
|
|
351
|
+
function getPhantomIconFromWalletStandard() {
|
|
352
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
const walletsAPI = navigator.wallets;
|
|
356
|
+
if (!walletsAPI || typeof walletsAPI.getWallets !== "function") {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
const walletsGetter = walletsAPI.getWallets();
|
|
361
|
+
if (walletsGetter && typeof walletsGetter.get === "function") {
|
|
362
|
+
const registeredWallets = walletsGetter.get();
|
|
363
|
+
const phantomWallet = registeredWallets.find((w) => w.name.toLowerCase().includes("phantom"));
|
|
364
|
+
if (phantomWallet?.icon) {
|
|
365
|
+
return phantomWallet.icon;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
} catch (error) {
|
|
369
|
+
}
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
async function discoverPhantomWallet(addressTypes) {
|
|
373
|
+
if (typeof window === "undefined") {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
if (!isPhantomExtensionInstalled()) {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
let icon = await getPhantomIconFromWalletStandard();
|
|
380
|
+
if (!icon) {
|
|
381
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
382
|
+
icon = await getPhantomIconFromWalletStandard();
|
|
383
|
+
}
|
|
384
|
+
if (!icon) {
|
|
385
|
+
icon = "https://phantom.app/img/phantom-icon-purple.png";
|
|
386
|
+
}
|
|
387
|
+
const plugins = [createExtensionPlugin()];
|
|
388
|
+
if (addressTypes.includes(ClientAddressType.solana)) {
|
|
389
|
+
plugins.push(createSolanaPlugin());
|
|
390
|
+
}
|
|
391
|
+
if (addressTypes.includes(ClientAddressType.ethereum)) {
|
|
392
|
+
plugins.push(createEthereumPlugin());
|
|
393
|
+
}
|
|
394
|
+
plugins.push(createAutoConfirmPlugin());
|
|
395
|
+
const phantomInstance = createPhantom({ plugins });
|
|
396
|
+
return {
|
|
397
|
+
id: "phantom",
|
|
398
|
+
name: "Phantom",
|
|
399
|
+
icon,
|
|
400
|
+
addressTypes,
|
|
401
|
+
providers: {
|
|
402
|
+
solana: addressTypes.includes(ClientAddressType.solana) ? phantomInstance.solana : void 0,
|
|
403
|
+
ethereum: addressTypes.includes(ClientAddressType.ethereum) ? phantomInstance.ethereum : void 0
|
|
404
|
+
},
|
|
405
|
+
isPhantom: true,
|
|
406
|
+
phantomInstance
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
async function discoverWallets(addressTypes) {
|
|
410
|
+
const requestedAddressTypes = addressTypes || [];
|
|
411
|
+
debug.log(DebugCategory.BROWSER_SDK, "Starting all wallet discovery methods", {
|
|
412
|
+
addressTypes: requestedAddressTypes
|
|
413
|
+
});
|
|
414
|
+
const [phantomWallet, solanaWallets, ethereumWallets] = await Promise.all([
|
|
415
|
+
discoverPhantomWallet(requestedAddressTypes),
|
|
416
|
+
discoverSolanaWallets(),
|
|
417
|
+
discoverEthereumWallets()
|
|
418
|
+
]);
|
|
419
|
+
debug.log(DebugCategory.BROWSER_SDK, "All wallet discovery methods completed", {
|
|
420
|
+
phantomFound: !!phantomWallet,
|
|
421
|
+
solanaWalletsCount: solanaWallets.length,
|
|
422
|
+
ethereumWalletsCount: ethereumWallets.length,
|
|
423
|
+
solanaWalletIds: solanaWallets.map((w) => w.id),
|
|
424
|
+
ethereumWalletIds: ethereumWallets.map((w) => w.id)
|
|
425
|
+
});
|
|
426
|
+
const walletMap = /* @__PURE__ */ new Map();
|
|
427
|
+
if (phantomWallet) {
|
|
428
|
+
walletMap.set("phantom", phantomWallet);
|
|
429
|
+
}
|
|
430
|
+
for (const wallet of [...solanaWallets, ...ethereumWallets]) {
|
|
431
|
+
const existing = walletMap.get(wallet.id);
|
|
432
|
+
if (existing) {
|
|
433
|
+
const mergedAddressTypes = Array.from(/* @__PURE__ */ new Set([...existing.addressTypes, ...wallet.addressTypes]));
|
|
434
|
+
const mergedProviders = {
|
|
435
|
+
...existing.providers,
|
|
436
|
+
...wallet.providers
|
|
437
|
+
};
|
|
438
|
+
const mergedWallet = {
|
|
439
|
+
...existing,
|
|
440
|
+
addressTypes: mergedAddressTypes,
|
|
441
|
+
// Prefer icon from the most recent discovery
|
|
442
|
+
icon: wallet.icon || existing.icon,
|
|
443
|
+
providers: mergedProviders
|
|
444
|
+
};
|
|
445
|
+
walletMap.set(wallet.id, mergedWallet);
|
|
446
|
+
debug.log(DebugCategory.BROWSER_SDK, "Merged wallet by ID", {
|
|
447
|
+
walletName: wallet.name,
|
|
448
|
+
walletId: wallet.id,
|
|
449
|
+
existingAddressTypes: existing.addressTypes,
|
|
450
|
+
newAddressTypes: wallet.addressTypes,
|
|
451
|
+
mergedAddressTypes,
|
|
452
|
+
existingProviders: Object.keys(existing.providers || {}),
|
|
453
|
+
newProviders: Object.keys(wallet.providers || {}),
|
|
454
|
+
mergedProviders: Object.keys(mergedProviders)
|
|
455
|
+
});
|
|
456
|
+
debug.log(DebugCategory.BROWSER_SDK, "Merged wallet from multiple discovery methods", {
|
|
457
|
+
walletId: wallet.id,
|
|
458
|
+
walletName: wallet.name,
|
|
459
|
+
existingAddressTypes: existing.addressTypes,
|
|
460
|
+
newAddressTypes: wallet.addressTypes,
|
|
461
|
+
mergedAddressTypes
|
|
462
|
+
});
|
|
463
|
+
} else {
|
|
464
|
+
walletMap.set(wallet.id, wallet);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return Array.from(walletMap.values());
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/providers/injected/chains/InjectedWalletSolanaChain.ts
|
|
471
|
+
import { EventEmitter } from "eventemitter3";
|
|
472
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
473
|
+
var InjectedWalletSolanaChain = class {
|
|
474
|
+
constructor(provider, walletId, walletName) {
|
|
475
|
+
this.eventEmitter = new EventEmitter();
|
|
476
|
+
this._connected = false;
|
|
477
|
+
this._publicKey = null;
|
|
478
|
+
this.provider = provider;
|
|
479
|
+
this.walletId = walletId;
|
|
480
|
+
this.walletName = walletName;
|
|
481
|
+
this.setupEventListeners();
|
|
482
|
+
}
|
|
483
|
+
get connected() {
|
|
484
|
+
return this._connected;
|
|
485
|
+
}
|
|
486
|
+
get publicKey() {
|
|
487
|
+
return this._publicKey;
|
|
488
|
+
}
|
|
489
|
+
async connect(options) {
|
|
490
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect", {
|
|
491
|
+
walletId: this.walletId,
|
|
492
|
+
walletName: this.walletName,
|
|
493
|
+
onlyIfTrusted: options?.onlyIfTrusted
|
|
494
|
+
});
|
|
495
|
+
try {
|
|
496
|
+
const result = await this.provider.connect(options);
|
|
497
|
+
if (typeof result === "string") {
|
|
498
|
+
this._connected = true;
|
|
499
|
+
this._publicKey = result;
|
|
500
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
|
|
501
|
+
walletId: this.walletId,
|
|
502
|
+
walletName: this.walletName,
|
|
503
|
+
publicKey: result
|
|
504
|
+
});
|
|
505
|
+
return { publicKey: result };
|
|
506
|
+
}
|
|
507
|
+
if (typeof result === "object" && result !== null && "publicKey" in result) {
|
|
508
|
+
this._connected = true;
|
|
509
|
+
this._publicKey = result.publicKey;
|
|
510
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
|
|
511
|
+
walletId: this.walletId,
|
|
512
|
+
walletName: this.walletName,
|
|
513
|
+
publicKey: result.publicKey
|
|
514
|
+
});
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
518
|
+
const firstAccount = result[0];
|
|
519
|
+
if (typeof firstAccount === "object" && firstAccount !== null && "address" in firstAccount) {
|
|
520
|
+
this._connected = true;
|
|
521
|
+
this._publicKey = firstAccount.address;
|
|
522
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connected", {
|
|
523
|
+
walletId: this.walletId,
|
|
524
|
+
walletName: this.walletName,
|
|
525
|
+
publicKey: firstAccount.address
|
|
526
|
+
});
|
|
527
|
+
return { publicKey: firstAccount.address };
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
throw new Error("Unexpected connect result format");
|
|
531
|
+
} catch (error) {
|
|
532
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana connect failed", {
|
|
533
|
+
walletId: this.walletId,
|
|
534
|
+
walletName: this.walletName,
|
|
535
|
+
error: error instanceof Error ? error.message : String(error)
|
|
536
|
+
});
|
|
537
|
+
throw error;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
async disconnect() {
|
|
541
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnect", {
|
|
542
|
+
walletId: this.walletId,
|
|
543
|
+
walletName: this.walletName
|
|
544
|
+
});
|
|
545
|
+
try {
|
|
546
|
+
await this.provider.disconnect();
|
|
547
|
+
this._connected = false;
|
|
548
|
+
this._publicKey = null;
|
|
549
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnected", {
|
|
550
|
+
walletId: this.walletId,
|
|
551
|
+
walletName: this.walletName
|
|
552
|
+
});
|
|
553
|
+
} catch (error) {
|
|
554
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana disconnect failed", {
|
|
555
|
+
walletId: this.walletId,
|
|
556
|
+
walletName: this.walletName,
|
|
557
|
+
error: error instanceof Error ? error.message : String(error)
|
|
558
|
+
});
|
|
559
|
+
throw error;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
async signMessage(message) {
|
|
563
|
+
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
564
|
+
const messagePreview = typeof message === "string" ? message.substring(0, 50) : `${messageBytes.length} bytes`;
|
|
565
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signMessage", {
|
|
566
|
+
walletId: this.walletId,
|
|
567
|
+
walletName: this.walletName,
|
|
568
|
+
messagePreview,
|
|
569
|
+
messageLength: messageBytes.length
|
|
570
|
+
});
|
|
571
|
+
try {
|
|
572
|
+
const result = await this.provider.signMessage(message);
|
|
573
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signMessage success", {
|
|
574
|
+
walletId: this.walletId,
|
|
575
|
+
walletName: this.walletName,
|
|
576
|
+
signatureLength: result.signature.length
|
|
577
|
+
});
|
|
578
|
+
return {
|
|
579
|
+
signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer2.from(result.signature, "base64")),
|
|
580
|
+
publicKey: result.publicKey || this._publicKey || ""
|
|
581
|
+
};
|
|
582
|
+
} catch (error) {
|
|
583
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signMessage failed", {
|
|
584
|
+
walletId: this.walletId,
|
|
585
|
+
walletName: this.walletName,
|
|
586
|
+
error: error instanceof Error ? error.message : String(error)
|
|
587
|
+
});
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
async signTransaction(transaction) {
|
|
592
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signTransaction", {
|
|
593
|
+
walletId: this.walletId,
|
|
594
|
+
walletName: this.walletName
|
|
595
|
+
});
|
|
596
|
+
try {
|
|
597
|
+
const result = await this.provider.signTransaction(transaction);
|
|
598
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signTransaction success", {
|
|
599
|
+
walletId: this.walletId,
|
|
600
|
+
walletName: this.walletName
|
|
601
|
+
});
|
|
602
|
+
return result;
|
|
603
|
+
} catch (error) {
|
|
604
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signTransaction failed", {
|
|
605
|
+
walletId: this.walletId,
|
|
606
|
+
walletName: this.walletName,
|
|
607
|
+
error: error instanceof Error ? error.message : String(error)
|
|
608
|
+
});
|
|
609
|
+
throw error;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
async signAndSendTransaction(transaction) {
|
|
613
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendTransaction", {
|
|
614
|
+
walletId: this.walletId,
|
|
615
|
+
walletName: this.walletName
|
|
616
|
+
});
|
|
617
|
+
try {
|
|
618
|
+
const result = await this.provider.signAndSendTransaction(transaction);
|
|
619
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendTransaction success", {
|
|
620
|
+
walletId: this.walletId,
|
|
621
|
+
walletName: this.walletName,
|
|
622
|
+
signature: result.signature
|
|
623
|
+
});
|
|
624
|
+
return result;
|
|
625
|
+
} catch (error) {
|
|
626
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendTransaction failed", {
|
|
627
|
+
walletId: this.walletId,
|
|
628
|
+
walletName: this.walletName,
|
|
629
|
+
error: error instanceof Error ? error.message : String(error)
|
|
630
|
+
});
|
|
631
|
+
throw error;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
async signAllTransactions(transactions) {
|
|
635
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAllTransactions", {
|
|
636
|
+
walletId: this.walletId,
|
|
637
|
+
walletName: this.walletName,
|
|
638
|
+
transactionCount: transactions.length
|
|
639
|
+
});
|
|
640
|
+
try {
|
|
641
|
+
const result = await this.provider.signAllTransactions(transactions);
|
|
642
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAllTransactions success", {
|
|
643
|
+
walletId: this.walletId,
|
|
644
|
+
walletName: this.walletName,
|
|
645
|
+
signedCount: result.length
|
|
646
|
+
});
|
|
647
|
+
return result;
|
|
648
|
+
} catch (error) {
|
|
649
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAllTransactions failed", {
|
|
650
|
+
walletId: this.walletId,
|
|
651
|
+
walletName: this.walletName,
|
|
652
|
+
error: error instanceof Error ? error.message : String(error)
|
|
653
|
+
});
|
|
654
|
+
throw error;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
async signAndSendAllTransactions(transactions) {
|
|
658
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendAllTransactions", {
|
|
659
|
+
walletId: this.walletId,
|
|
660
|
+
walletName: this.walletName,
|
|
661
|
+
transactionCount: transactions.length
|
|
662
|
+
});
|
|
663
|
+
try {
|
|
664
|
+
const result = await this.provider.signAndSendAllTransactions(transactions);
|
|
665
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendAllTransactions success", {
|
|
666
|
+
walletId: this.walletId,
|
|
667
|
+
walletName: this.walletName,
|
|
668
|
+
signatureCount: result.signatures.length
|
|
669
|
+
});
|
|
670
|
+
return result;
|
|
671
|
+
} catch (error) {
|
|
672
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Solana signAndSendAllTransactions failed", {
|
|
673
|
+
walletId: this.walletId,
|
|
674
|
+
walletName: this.walletName,
|
|
675
|
+
error: error instanceof Error ? error.message : String(error)
|
|
676
|
+
});
|
|
677
|
+
throw error;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
switchNetwork(_network) {
|
|
681
|
+
return Promise.resolve();
|
|
682
|
+
}
|
|
683
|
+
getPublicKey() {
|
|
684
|
+
return Promise.resolve(this._publicKey);
|
|
685
|
+
}
|
|
686
|
+
isConnected() {
|
|
687
|
+
return this._connected;
|
|
688
|
+
}
|
|
689
|
+
setupEventListeners() {
|
|
690
|
+
if (typeof this.provider.on === "function") {
|
|
691
|
+
this.provider.on("connect", (publicKey) => {
|
|
692
|
+
this._connected = true;
|
|
693
|
+
this._publicKey = publicKey;
|
|
694
|
+
this.eventEmitter.emit("connect", publicKey);
|
|
695
|
+
});
|
|
696
|
+
this.provider.on("disconnect", () => {
|
|
697
|
+
this._connected = false;
|
|
698
|
+
this._publicKey = null;
|
|
699
|
+
this.eventEmitter.emit("disconnect");
|
|
700
|
+
});
|
|
701
|
+
this.provider.on("accountChanged", (publicKey) => {
|
|
702
|
+
this._publicKey = publicKey;
|
|
703
|
+
this.eventEmitter.emit("accountChanged", publicKey);
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
on(event, listener) {
|
|
708
|
+
this.eventEmitter.on(event, listener);
|
|
709
|
+
}
|
|
710
|
+
off(event, listener) {
|
|
711
|
+
this.eventEmitter.off(event, listener);
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// src/providers/injected/chains/WalletStandardSolanaAdapter.ts
|
|
716
|
+
import { deserializeSolanaTransaction } from "@phantom/parsers";
|
|
717
|
+
import bs58 from "bs58";
|
|
718
|
+
var WalletStandardSolanaAdapter = class {
|
|
719
|
+
constructor(wallet, walletId, walletName) {
|
|
720
|
+
this._connected = false;
|
|
721
|
+
this._publicKey = null;
|
|
722
|
+
this.wallet = wallet;
|
|
723
|
+
this.walletId = walletId;
|
|
724
|
+
this.walletName = walletName;
|
|
725
|
+
}
|
|
726
|
+
get connected() {
|
|
727
|
+
return this._connected;
|
|
728
|
+
}
|
|
729
|
+
get publicKey() {
|
|
730
|
+
return this._publicKey;
|
|
731
|
+
}
|
|
732
|
+
async connect(_options) {
|
|
733
|
+
try {
|
|
734
|
+
const connectFeature = this.wallet.features?.["standard:connect"];
|
|
735
|
+
if (!connectFeature || typeof connectFeature.connect !== "function") {
|
|
736
|
+
throw new Error("Wallet Standard connect feature not available");
|
|
737
|
+
}
|
|
738
|
+
const connectResult = await connectFeature.connect();
|
|
739
|
+
let accounts;
|
|
740
|
+
if (Array.isArray(connectResult) && connectResult.length > 0) {
|
|
741
|
+
accounts = connectResult;
|
|
742
|
+
} else if (this.wallet.accounts && this.wallet.accounts.length > 0) {
|
|
743
|
+
accounts = Array.from(this.wallet.accounts);
|
|
744
|
+
}
|
|
745
|
+
if (!accounts || accounts.length === 0) {
|
|
746
|
+
throw new Error("No accounts available after connecting to wallet");
|
|
747
|
+
}
|
|
748
|
+
const firstAccount = accounts[0];
|
|
749
|
+
if (!firstAccount) {
|
|
750
|
+
throw new Error("First account is null or undefined");
|
|
751
|
+
}
|
|
752
|
+
let address;
|
|
753
|
+
if (typeof firstAccount === "string") {
|
|
754
|
+
address = firstAccount;
|
|
755
|
+
} else if (typeof firstAccount === "object" && firstAccount !== null) {
|
|
756
|
+
address = firstAccount.address || firstAccount.publicKey?.toString() || (firstAccount.publicKey instanceof Uint8Array ? Buffer.from(firstAccount.publicKey).toString("hex") : void 0);
|
|
757
|
+
}
|
|
758
|
+
if (!address) {
|
|
759
|
+
throw new Error(
|
|
760
|
+
`Could not extract address from account. Account structure: ${JSON.stringify(firstAccount, null, 2)}`
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
this._connected = true;
|
|
764
|
+
this._publicKey = address;
|
|
765
|
+
return { publicKey: address };
|
|
766
|
+
} catch (error) {
|
|
767
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana connect failed", {
|
|
768
|
+
walletId: this.walletId,
|
|
769
|
+
walletName: this.walletName,
|
|
770
|
+
error: error instanceof Error ? error.message : String(error)
|
|
771
|
+
});
|
|
772
|
+
throw error;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async disconnect() {
|
|
776
|
+
try {
|
|
777
|
+
const disconnectFeature = this.wallet.features?.["standard:disconnect"];
|
|
778
|
+
if (disconnectFeature && typeof disconnectFeature.disconnect === "function") {
|
|
779
|
+
await disconnectFeature.disconnect();
|
|
780
|
+
}
|
|
781
|
+
this._connected = false;
|
|
782
|
+
this._publicKey = null;
|
|
783
|
+
} catch (error) {
|
|
784
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana disconnect failed", {
|
|
785
|
+
walletId: this.walletId,
|
|
786
|
+
walletName: this.walletName,
|
|
787
|
+
error: error instanceof Error ? error.message : String(error)
|
|
788
|
+
});
|
|
789
|
+
throw error;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
async signMessage(message) {
|
|
793
|
+
try {
|
|
794
|
+
const signMessageFeature = this.wallet.features?.["solana:signMessage"];
|
|
795
|
+
if (!signMessageFeature || typeof signMessageFeature.signMessage !== "function") {
|
|
796
|
+
throw new Error("Wallet Standard signMessage feature not available");
|
|
797
|
+
}
|
|
798
|
+
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
799
|
+
const result = await signMessageFeature.signMessage({
|
|
800
|
+
message: messageBytes,
|
|
801
|
+
account: this.wallet.accounts?.[0]
|
|
802
|
+
});
|
|
803
|
+
if (!Array.isArray(result) || result.length === 0) {
|
|
804
|
+
throw new Error(`Expected array result from signMessage, got: ${typeof result}`);
|
|
805
|
+
}
|
|
806
|
+
const signedMessageResult = result[0];
|
|
807
|
+
if (!signedMessageResult || !signedMessageResult.signature) {
|
|
808
|
+
throw new Error(`Invalid signMessage result structure: ${JSON.stringify(result)}`);
|
|
809
|
+
}
|
|
810
|
+
const signature = this.parseUint8Array(signedMessageResult.signature);
|
|
811
|
+
if (signature.length === 0) {
|
|
812
|
+
throw new Error(`Signature is empty`);
|
|
813
|
+
}
|
|
814
|
+
const publicKey = signedMessageResult.account?.address || this.wallet.accounts?.[0]?.address || this._publicKey || "";
|
|
815
|
+
return { signature, publicKey };
|
|
816
|
+
} catch (error) {
|
|
817
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signMessage failed", {
|
|
818
|
+
walletId: this.walletId,
|
|
819
|
+
walletName: this.walletName,
|
|
820
|
+
error: error instanceof Error ? error.message : String(error)
|
|
821
|
+
});
|
|
822
|
+
throw error;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
async signTransaction(transaction) {
|
|
826
|
+
try {
|
|
827
|
+
const signTransactionFeature = this.wallet.features?.["solana:signTransaction"];
|
|
828
|
+
if (!signTransactionFeature || typeof signTransactionFeature.signTransaction !== "function") {
|
|
829
|
+
throw new Error("Wallet Standard signTransaction feature not available");
|
|
830
|
+
}
|
|
831
|
+
if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
|
|
832
|
+
throw new Error("No accounts available. Please connect first.");
|
|
833
|
+
}
|
|
834
|
+
const account = this.wallet.accounts[0];
|
|
835
|
+
const serializedTransaction = this.serializeTransaction(transaction);
|
|
836
|
+
const results = await signTransactionFeature.signTransaction({
|
|
837
|
+
transaction: serializedTransaction,
|
|
838
|
+
account
|
|
839
|
+
});
|
|
840
|
+
let transactionData;
|
|
841
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
842
|
+
const firstItem = results[0];
|
|
843
|
+
if (firstItem && typeof firstItem === "object") {
|
|
844
|
+
transactionData = firstItem.signedTransaction || firstItem.transaction;
|
|
845
|
+
}
|
|
846
|
+
} else if (results && typeof results === "object" && !Array.isArray(results)) {
|
|
847
|
+
transactionData = results.transaction || results.signedTransaction;
|
|
848
|
+
}
|
|
849
|
+
if (!transactionData) {
|
|
850
|
+
throw new Error("No transaction data found in Wallet Standard result");
|
|
851
|
+
}
|
|
852
|
+
const signedBytes = this.parseUint8Array(transactionData);
|
|
853
|
+
if (signedBytes.length === 0) {
|
|
854
|
+
throw new Error("Empty signed transaction returned from Wallet Standard");
|
|
855
|
+
}
|
|
856
|
+
const signedTx = deserializeSolanaTransaction(signedBytes);
|
|
857
|
+
return signedTx;
|
|
858
|
+
} catch (error) {
|
|
859
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signTransaction failed", {
|
|
860
|
+
walletId: this.walletId,
|
|
861
|
+
walletName: this.walletName,
|
|
862
|
+
error: error instanceof Error ? error.message : String(error)
|
|
863
|
+
});
|
|
864
|
+
throw error;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
async signAndSendTransaction(transaction) {
|
|
868
|
+
try {
|
|
869
|
+
const signAndSendTransactionFeature = this.wallet.features?.["solana:signAndSendTransaction"];
|
|
870
|
+
if (!signAndSendTransactionFeature || typeof signAndSendTransactionFeature.signAndSendTransaction !== "function") {
|
|
871
|
+
throw new Error("Wallet Standard signAndSendTransaction feature not available");
|
|
872
|
+
}
|
|
873
|
+
if (!this.wallet.accounts || this.wallet.accounts.length === 0) {
|
|
874
|
+
throw new Error("No accounts available. Please connect first.");
|
|
875
|
+
}
|
|
876
|
+
const account = this.wallet.accounts[0];
|
|
877
|
+
const chain = account.chains?.[0] || "solana:mainnet";
|
|
878
|
+
const serializedTransaction = this.serializeTransaction(transaction);
|
|
879
|
+
const results = await signAndSendTransactionFeature.signAndSendTransaction({
|
|
880
|
+
transaction: serializedTransaction,
|
|
881
|
+
account,
|
|
882
|
+
chain
|
|
883
|
+
});
|
|
884
|
+
let signatureOutput;
|
|
885
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
886
|
+
signatureOutput = results[0];
|
|
887
|
+
} else if (results && typeof results === "object" && !Array.isArray(results)) {
|
|
888
|
+
signatureOutput = results;
|
|
889
|
+
} else {
|
|
890
|
+
throw new Error("Invalid signAndSendTransaction result format");
|
|
891
|
+
}
|
|
892
|
+
if (!signatureOutput.signature) {
|
|
893
|
+
throw new Error("No signature found in signAndSendTransaction result");
|
|
894
|
+
}
|
|
895
|
+
const signatureBytes = this.parseUint8Array(signatureOutput.signature);
|
|
896
|
+
const signature = bs58.encode(signatureBytes);
|
|
897
|
+
return { signature };
|
|
898
|
+
} catch (error) {
|
|
899
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signAndSendTransaction failed", {
|
|
900
|
+
walletId: this.walletId,
|
|
901
|
+
walletName: this.walletName,
|
|
902
|
+
error: error instanceof Error ? error.message : String(error)
|
|
903
|
+
});
|
|
904
|
+
throw error;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
async signAllTransactions(transactions) {
|
|
908
|
+
try {
|
|
909
|
+
const signedTransactions = [];
|
|
910
|
+
for (const transaction of transactions) {
|
|
911
|
+
const signedTx = await this.signTransaction(transaction);
|
|
912
|
+
signedTransactions.push(signedTx);
|
|
913
|
+
}
|
|
914
|
+
return signedTransactions;
|
|
915
|
+
} catch (error) {
|
|
916
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signAllTransactions failed", {
|
|
917
|
+
walletId: this.walletId,
|
|
918
|
+
walletName: this.walletName,
|
|
919
|
+
error: error instanceof Error ? error.message : String(error)
|
|
920
|
+
});
|
|
921
|
+
throw error;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
async signAndSendAllTransactions(transactions) {
|
|
925
|
+
try {
|
|
926
|
+
const signatures = [];
|
|
927
|
+
for (const transaction of transactions) {
|
|
928
|
+
const result = await this.signAndSendTransaction(transaction);
|
|
929
|
+
signatures.push(result.signature);
|
|
930
|
+
}
|
|
931
|
+
return { signatures };
|
|
932
|
+
} catch (error) {
|
|
933
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana signAndSendAllTransactions failed", {
|
|
934
|
+
walletId: this.walletId,
|
|
935
|
+
walletName: this.walletName,
|
|
936
|
+
error: error instanceof Error ? error.message : String(error)
|
|
937
|
+
});
|
|
938
|
+
throw error;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
async switchNetwork(network) {
|
|
942
|
+
try {
|
|
943
|
+
const switchNetworkFeature = this.wallet.features?.["standard:switchNetwork"];
|
|
944
|
+
if (switchNetworkFeature && typeof switchNetworkFeature.switchNetwork === "function") {
|
|
945
|
+
const chainId = network === "mainnet" ? "solana:mainnet" : "solana:devnet";
|
|
946
|
+
await switchNetworkFeature.switchNetwork({ chain: chainId });
|
|
947
|
+
}
|
|
948
|
+
} catch (error) {
|
|
949
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet Standard Solana switchNetwork failed", {
|
|
950
|
+
walletId: this.walletId,
|
|
951
|
+
walletName: this.walletName,
|
|
952
|
+
network,
|
|
953
|
+
error: error instanceof Error ? error.message : String(error)
|
|
954
|
+
});
|
|
955
|
+
throw error;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
getPublicKey() {
|
|
959
|
+
return Promise.resolve(this._publicKey);
|
|
960
|
+
}
|
|
961
|
+
isConnected() {
|
|
962
|
+
return this._connected;
|
|
963
|
+
}
|
|
964
|
+
on(_event, _listener) {
|
|
965
|
+
const eventsFeature = this.wallet.features?.["standard:events"];
|
|
966
|
+
if (eventsFeature && typeof eventsFeature.on === "function") {
|
|
967
|
+
eventsFeature.on(_event, _listener);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
off(_event, _listener) {
|
|
971
|
+
const eventsFeature = this.wallet.features?.["standard:events"];
|
|
972
|
+
if (eventsFeature && typeof eventsFeature.off === "function") {
|
|
973
|
+
eventsFeature.off(_event, _listener);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Serialize a transaction to Uint8Array for Wallet Standard API
|
|
978
|
+
*/
|
|
979
|
+
serializeTransaction(transaction) {
|
|
980
|
+
if (typeof transaction.serialize === "function") {
|
|
981
|
+
return transaction.serialize({
|
|
982
|
+
requireAllSignatures: false,
|
|
983
|
+
verifySignatures: false
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
if (transaction instanceof Uint8Array) {
|
|
987
|
+
return transaction;
|
|
988
|
+
}
|
|
989
|
+
return new Uint8Array(0);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Parse a Uint8Array from various formats
|
|
993
|
+
* Handles: Uint8Array, Array, object with numeric keys (JSON-serialized Uint8Array)
|
|
994
|
+
*/
|
|
995
|
+
parseUint8Array(value) {
|
|
996
|
+
if (value instanceof Uint8Array) {
|
|
997
|
+
return value;
|
|
998
|
+
}
|
|
999
|
+
if (Array.isArray(value)) {
|
|
1000
|
+
return new Uint8Array(value);
|
|
1001
|
+
}
|
|
1002
|
+
if (typeof value === "object" && value !== null) {
|
|
1003
|
+
const keys = Object.keys(value).map(Number).filter((k) => !isNaN(k) && k >= 0).sort((a, b) => a - b);
|
|
1004
|
+
if (keys.length > 0) {
|
|
1005
|
+
const maxKey = Math.max(...keys);
|
|
1006
|
+
const array = new Uint8Array(maxKey + 1);
|
|
1007
|
+
for (const key of keys) {
|
|
1008
|
+
array[key] = Number(value[key]) || 0;
|
|
1009
|
+
}
|
|
1010
|
+
return array;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return new Uint8Array(0);
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
// src/providers/injected/chains/InjectedWalletEthereumChain.ts
|
|
1018
|
+
import { EventEmitter as EventEmitter2 } from "eventemitter3";
|
|
1019
|
+
var InjectedWalletEthereumChain = class {
|
|
1020
|
+
constructor(provider, walletId, walletName) {
|
|
1021
|
+
this.eventEmitter = new EventEmitter2();
|
|
1022
|
+
this._connected = false;
|
|
1023
|
+
this._chainId = "0x1";
|
|
1024
|
+
this._accounts = [];
|
|
1025
|
+
this.provider = provider;
|
|
1026
|
+
this.walletId = walletId;
|
|
1027
|
+
this.walletName = walletName;
|
|
1028
|
+
this.setupEventListeners();
|
|
1029
|
+
}
|
|
1030
|
+
get connected() {
|
|
1031
|
+
return this._connected;
|
|
1032
|
+
}
|
|
1033
|
+
get chainId() {
|
|
1034
|
+
return this._chainId;
|
|
1035
|
+
}
|
|
1036
|
+
get accounts() {
|
|
1037
|
+
return this._accounts;
|
|
1038
|
+
}
|
|
1039
|
+
async request(args) {
|
|
1040
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request", {
|
|
1041
|
+
walletId: this.walletId,
|
|
1042
|
+
walletName: this.walletName,
|
|
1043
|
+
method: args.method
|
|
1044
|
+
});
|
|
1045
|
+
try {
|
|
1046
|
+
const requiresAuth = [
|
|
1047
|
+
"personal_sign",
|
|
1048
|
+
"eth_sign",
|
|
1049
|
+
"eth_signTypedData",
|
|
1050
|
+
"eth_signTypedData_v4",
|
|
1051
|
+
"eth_sendTransaction",
|
|
1052
|
+
"eth_signTransaction"
|
|
1053
|
+
].includes(args.method);
|
|
1054
|
+
if (requiresAuth && (!this._connected || this._accounts.length === 0)) {
|
|
1055
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Method requires authorization, ensuring connection", {
|
|
1056
|
+
walletId: this.walletId,
|
|
1057
|
+
walletName: this.walletName,
|
|
1058
|
+
method: args.method
|
|
1059
|
+
});
|
|
1060
|
+
await this.connect();
|
|
1061
|
+
}
|
|
1062
|
+
const result = await this.provider.request(args);
|
|
1063
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request success", {
|
|
1064
|
+
walletId: this.walletId,
|
|
1065
|
+
walletName: this.walletName,
|
|
1066
|
+
method: args.method
|
|
1067
|
+
});
|
|
1068
|
+
return result;
|
|
1069
|
+
} catch (error) {
|
|
1070
|
+
if (error?.code === 4100) {
|
|
1071
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Got 4100 Unauthorized, attempting to re-authorize", {
|
|
1072
|
+
walletId: this.walletId,
|
|
1073
|
+
walletName: this.walletName,
|
|
1074
|
+
method: args.method
|
|
1075
|
+
});
|
|
1076
|
+
try {
|
|
1077
|
+
await this.provider.request({ method: "eth_requestAccounts" });
|
|
1078
|
+
const result = await this.provider.request(args);
|
|
1079
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request success (after re-auth)", {
|
|
1080
|
+
walletId: this.walletId,
|
|
1081
|
+
walletName: this.walletName,
|
|
1082
|
+
method: args.method
|
|
1083
|
+
});
|
|
1084
|
+
return result;
|
|
1085
|
+
} catch (retryError) {
|
|
1086
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Failed after re-authorization", {
|
|
1087
|
+
walletId: this.walletId,
|
|
1088
|
+
walletName: this.walletName,
|
|
1089
|
+
method: args.method,
|
|
1090
|
+
error: retryError instanceof Error ? retryError.message : String(retryError)
|
|
1091
|
+
});
|
|
1092
|
+
throw retryError;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum request failed", {
|
|
1096
|
+
walletId: this.walletId,
|
|
1097
|
+
walletName: this.walletName,
|
|
1098
|
+
method: args.method,
|
|
1099
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1100
|
+
errorCode: error?.code
|
|
1101
|
+
});
|
|
1102
|
+
throw error;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
async connect() {
|
|
1106
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum connect", {
|
|
1107
|
+
walletId: this.walletId,
|
|
1108
|
+
walletName: this.walletName
|
|
1109
|
+
});
|
|
1110
|
+
try {
|
|
1111
|
+
const accounts = await this.provider.request({ method: "eth_requestAccounts" });
|
|
1112
|
+
this._connected = accounts.length > 0;
|
|
1113
|
+
this._accounts = accounts;
|
|
1114
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum connected (via eth_requestAccounts)", {
|
|
1115
|
+
walletId: this.walletId,
|
|
1116
|
+
walletName: this.walletName,
|
|
1117
|
+
accountCount: accounts.length,
|
|
1118
|
+
accounts
|
|
1119
|
+
});
|
|
1120
|
+
return accounts;
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum connect failed", {
|
|
1123
|
+
walletId: this.walletId,
|
|
1124
|
+
walletName: this.walletName,
|
|
1125
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1126
|
+
});
|
|
1127
|
+
throw error;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
async disconnect() {
|
|
1131
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum disconnect", {
|
|
1132
|
+
walletId: this.walletId,
|
|
1133
|
+
walletName: this.walletName
|
|
1134
|
+
});
|
|
1135
|
+
try {
|
|
1136
|
+
await this.provider.disconnect();
|
|
1137
|
+
this._connected = false;
|
|
1138
|
+
this._accounts = [];
|
|
1139
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum disconnected", {
|
|
1140
|
+
walletId: this.walletId,
|
|
1141
|
+
walletName: this.walletName
|
|
1142
|
+
});
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum disconnect failed", {
|
|
1145
|
+
walletId: this.walletId,
|
|
1146
|
+
walletName: this.walletName,
|
|
1147
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1148
|
+
});
|
|
1149
|
+
throw error;
|
|
1150
|
+
}
|
|
31
1151
|
}
|
|
32
|
-
|
|
33
|
-
|
|
1152
|
+
async signPersonalMessage(message, address) {
|
|
1153
|
+
const messagePreview = message.length > 50 ? message.substring(0, 50) + "..." : message;
|
|
1154
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage", {
|
|
1155
|
+
walletId: this.walletId,
|
|
1156
|
+
walletName: this.walletName,
|
|
1157
|
+
messagePreview,
|
|
1158
|
+
messageLength: message.length,
|
|
1159
|
+
address
|
|
1160
|
+
});
|
|
1161
|
+
try {
|
|
1162
|
+
const providerConnected = this.provider.isConnected?.() || this.provider.connected || false;
|
|
1163
|
+
if (!this._connected || this._accounts.length === 0 || !providerConnected) {
|
|
1164
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Not connected, attempting to connect before signing", {
|
|
1165
|
+
walletId: this.walletId,
|
|
1166
|
+
walletName: this.walletName,
|
|
1167
|
+
internalConnected: this._connected,
|
|
1168
|
+
accountsLength: this._accounts.length,
|
|
1169
|
+
providerConnected
|
|
1170
|
+
});
|
|
1171
|
+
await this.connect();
|
|
1172
|
+
}
|
|
1173
|
+
const normalizedAddress = address.toLowerCase();
|
|
1174
|
+
const normalizedAccounts = this._accounts.map((acc) => acc.toLowerCase());
|
|
1175
|
+
if (!normalizedAccounts.includes(normalizedAddress)) {
|
|
1176
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Address not in connected accounts, refreshing connection", {
|
|
1177
|
+
walletId: this.walletId,
|
|
1178
|
+
walletName: this.walletName,
|
|
1179
|
+
requestedAddress: address,
|
|
1180
|
+
connectedAccounts: this._accounts
|
|
1181
|
+
});
|
|
1182
|
+
const currentAccounts = await this.getAccounts();
|
|
1183
|
+
const normalizedCurrentAccounts = currentAccounts.map((acc) => acc.toLowerCase());
|
|
1184
|
+
if (!normalizedCurrentAccounts.includes(normalizedAddress)) {
|
|
1185
|
+
throw new Error(`Address ${address} is not connected. Connected accounts: ${currentAccounts.join(", ")}`);
|
|
1186
|
+
}
|
|
1187
|
+
this._accounts = currentAccounts;
|
|
1188
|
+
}
|
|
1189
|
+
if (typeof this.provider.signPersonalMessage === "function") {
|
|
1190
|
+
const result2 = await this.provider.signPersonalMessage(message, address);
|
|
1191
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage success", {
|
|
1192
|
+
walletId: this.walletId,
|
|
1193
|
+
walletName: this.walletName,
|
|
1194
|
+
signatureLength: result2.length
|
|
1195
|
+
});
|
|
1196
|
+
return result2;
|
|
1197
|
+
}
|
|
1198
|
+
const result = await this.request({
|
|
1199
|
+
method: "personal_sign",
|
|
1200
|
+
params: [message, address]
|
|
1201
|
+
});
|
|
1202
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage success", {
|
|
1203
|
+
walletId: this.walletId,
|
|
1204
|
+
walletName: this.walletName,
|
|
1205
|
+
signatureLength: result.length
|
|
1206
|
+
});
|
|
1207
|
+
return result;
|
|
1208
|
+
} catch (error) {
|
|
1209
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signPersonalMessage failed", {
|
|
1210
|
+
walletId: this.walletId,
|
|
1211
|
+
walletName: this.walletName,
|
|
1212
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1213
|
+
errorCode: error?.code
|
|
1214
|
+
});
|
|
1215
|
+
throw error;
|
|
1216
|
+
}
|
|
34
1217
|
}
|
|
35
|
-
|
|
36
|
-
|
|
1218
|
+
async signTypedData(typedData, address) {
|
|
1219
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData", {
|
|
1220
|
+
walletId: this.walletId,
|
|
1221
|
+
walletName: this.walletName,
|
|
1222
|
+
primaryType: typedData?.primaryType,
|
|
1223
|
+
address
|
|
1224
|
+
});
|
|
1225
|
+
try {
|
|
1226
|
+
if (typeof this.provider.signTypedData === "function") {
|
|
1227
|
+
const result2 = await this.provider.signTypedData(typedData, address);
|
|
1228
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData success", {
|
|
1229
|
+
walletId: this.walletId,
|
|
1230
|
+
walletName: this.walletName,
|
|
1231
|
+
signatureLength: result2.length
|
|
1232
|
+
});
|
|
1233
|
+
return result2;
|
|
1234
|
+
}
|
|
1235
|
+
const result = await this.request({
|
|
1236
|
+
method: "eth_signTypedData_v4",
|
|
1237
|
+
params: [address, typedData]
|
|
1238
|
+
});
|
|
1239
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData success", {
|
|
1240
|
+
walletId: this.walletId,
|
|
1241
|
+
walletName: this.walletName,
|
|
1242
|
+
signatureLength: result.length
|
|
1243
|
+
});
|
|
1244
|
+
return result;
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTypedData failed", {
|
|
1247
|
+
walletId: this.walletId,
|
|
1248
|
+
walletName: this.walletName,
|
|
1249
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1250
|
+
});
|
|
1251
|
+
throw error;
|
|
1252
|
+
}
|
|
37
1253
|
}
|
|
38
|
-
|
|
39
|
-
|
|
1254
|
+
async signTransaction(transaction) {
|
|
1255
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction", {
|
|
1256
|
+
walletId: this.walletId,
|
|
1257
|
+
walletName: this.walletName,
|
|
1258
|
+
from: transaction.from,
|
|
1259
|
+
to: transaction.to
|
|
1260
|
+
});
|
|
1261
|
+
try {
|
|
1262
|
+
if (typeof this.provider.signTransaction === "function") {
|
|
1263
|
+
const result2 = await this.provider.signTransaction(transaction);
|
|
1264
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction success", {
|
|
1265
|
+
walletId: this.walletId,
|
|
1266
|
+
walletName: this.walletName,
|
|
1267
|
+
signatureLength: result2.length
|
|
1268
|
+
});
|
|
1269
|
+
return result2;
|
|
1270
|
+
}
|
|
1271
|
+
const result = await this.request({
|
|
1272
|
+
method: "eth_signTransaction",
|
|
1273
|
+
params: [transaction]
|
|
1274
|
+
});
|
|
1275
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction success", {
|
|
1276
|
+
walletId: this.walletId,
|
|
1277
|
+
walletName: this.walletName,
|
|
1278
|
+
signatureLength: result.length
|
|
1279
|
+
});
|
|
1280
|
+
return result;
|
|
1281
|
+
} catch (error) {
|
|
1282
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum signTransaction failed", {
|
|
1283
|
+
walletId: this.walletId,
|
|
1284
|
+
walletName: this.walletName,
|
|
1285
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1286
|
+
});
|
|
1287
|
+
throw error;
|
|
1288
|
+
}
|
|
40
1289
|
}
|
|
41
|
-
|
|
42
|
-
|
|
1290
|
+
async sendTransaction(transaction) {
|
|
1291
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction", {
|
|
1292
|
+
walletId: this.walletId,
|
|
1293
|
+
walletName: this.walletName,
|
|
1294
|
+
from: transaction.from,
|
|
1295
|
+
to: transaction.to,
|
|
1296
|
+
value: transaction.value
|
|
1297
|
+
});
|
|
1298
|
+
try {
|
|
1299
|
+
if (typeof this.provider.sendTransaction === "function") {
|
|
1300
|
+
const result2 = await this.provider.sendTransaction(transaction);
|
|
1301
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction success", {
|
|
1302
|
+
walletId: this.walletId,
|
|
1303
|
+
walletName: this.walletName,
|
|
1304
|
+
txHash: result2
|
|
1305
|
+
});
|
|
1306
|
+
return result2;
|
|
1307
|
+
}
|
|
1308
|
+
const result = await this.request({
|
|
1309
|
+
method: "eth_sendTransaction",
|
|
1310
|
+
params: [transaction]
|
|
1311
|
+
});
|
|
1312
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction success", {
|
|
1313
|
+
walletId: this.walletId,
|
|
1314
|
+
walletName: this.walletName,
|
|
1315
|
+
txHash: result
|
|
1316
|
+
});
|
|
1317
|
+
return result;
|
|
1318
|
+
} catch (error) {
|
|
1319
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum sendTransaction failed", {
|
|
1320
|
+
walletId: this.walletId,
|
|
1321
|
+
walletName: this.walletName,
|
|
1322
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1323
|
+
});
|
|
1324
|
+
throw error;
|
|
1325
|
+
}
|
|
43
1326
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1327
|
+
async switchChain(chainId) {
|
|
1328
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum switchChain", {
|
|
1329
|
+
walletId: this.walletId,
|
|
1330
|
+
walletName: this.walletName,
|
|
1331
|
+
chainId
|
|
1332
|
+
});
|
|
1333
|
+
try {
|
|
1334
|
+
const hexChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? chainId : `0x${parseInt(chainId, 10).toString(16)}` : `0x${chainId.toString(16)}`;
|
|
1335
|
+
if (typeof this.provider.switchChain === "function") {
|
|
1336
|
+
await this.provider.switchChain(hexChainId);
|
|
1337
|
+
} else {
|
|
1338
|
+
await this.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hexChainId }] });
|
|
1339
|
+
}
|
|
1340
|
+
this._chainId = hexChainId;
|
|
1341
|
+
this.eventEmitter.emit("chainChanged", this._chainId);
|
|
1342
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum switchChain success", {
|
|
1343
|
+
walletId: this.walletId,
|
|
1344
|
+
walletName: this.walletName,
|
|
1345
|
+
chainId: hexChainId
|
|
1346
|
+
});
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum switchChain failed", {
|
|
1349
|
+
walletId: this.walletId,
|
|
1350
|
+
walletName: this.walletName,
|
|
1351
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1352
|
+
});
|
|
1353
|
+
throw error;
|
|
47
1354
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
};
|
|
55
|
-
if (this.callback) {
|
|
56
|
-
this.callback(debugMessage);
|
|
1355
|
+
}
|
|
1356
|
+
async getChainId() {
|
|
1357
|
+
if (typeof this.provider.getChainId === "function") {
|
|
1358
|
+
const chainId2 = await this.provider.getChainId();
|
|
1359
|
+
this._chainId = `0x${chainId2.toString(16)}`;
|
|
1360
|
+
return chainId2;
|
|
57
1361
|
}
|
|
1362
|
+
const chainId = await this.request({ method: "eth_chainId" });
|
|
1363
|
+
const parsed = parseInt(chainId, 16);
|
|
1364
|
+
this._chainId = chainId;
|
|
1365
|
+
return parsed;
|
|
58
1366
|
}
|
|
59
|
-
|
|
60
|
-
this.
|
|
1367
|
+
async getAccounts() {
|
|
1368
|
+
if (typeof this.provider.getAccounts === "function") {
|
|
1369
|
+
const accounts2 = await this.provider.getAccounts();
|
|
1370
|
+
this._accounts = accounts2;
|
|
1371
|
+
return accounts2;
|
|
1372
|
+
}
|
|
1373
|
+
const accounts = await this.request({ method: "eth_accounts" });
|
|
1374
|
+
this._accounts = accounts;
|
|
1375
|
+
return accounts;
|
|
61
1376
|
}
|
|
62
|
-
|
|
63
|
-
this.
|
|
1377
|
+
isConnected() {
|
|
1378
|
+
return this._connected;
|
|
64
1379
|
}
|
|
65
|
-
|
|
66
|
-
this.
|
|
1380
|
+
setupEventListeners() {
|
|
1381
|
+
if (typeof this.provider.on === "function") {
|
|
1382
|
+
this.provider.on("connect", (info) => {
|
|
1383
|
+
this._connected = true;
|
|
1384
|
+
this._chainId = info.chainId;
|
|
1385
|
+
this.eventEmitter.emit("connect", info);
|
|
1386
|
+
});
|
|
1387
|
+
this.provider.on("disconnect", (error) => {
|
|
1388
|
+
this._connected = false;
|
|
1389
|
+
this._accounts = [];
|
|
1390
|
+
this.eventEmitter.emit("disconnect", error);
|
|
1391
|
+
this.eventEmitter.emit("accountsChanged", []);
|
|
1392
|
+
});
|
|
1393
|
+
this.provider.on("accountsChanged", (accounts) => {
|
|
1394
|
+
this._accounts = accounts;
|
|
1395
|
+
this.eventEmitter.emit("accountsChanged", accounts);
|
|
1396
|
+
});
|
|
1397
|
+
this.provider.on("chainChanged", (chainId) => {
|
|
1398
|
+
this._chainId = chainId;
|
|
1399
|
+
this.eventEmitter.emit("chainChanged", chainId);
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
67
1402
|
}
|
|
68
|
-
|
|
69
|
-
this.
|
|
1403
|
+
on(event, listener) {
|
|
1404
|
+
this.eventEmitter.on(event, listener);
|
|
70
1405
|
}
|
|
71
|
-
|
|
72
|
-
this.
|
|
1406
|
+
off(event, listener) {
|
|
1407
|
+
this.eventEmitter.off(event, listener);
|
|
73
1408
|
}
|
|
74
1409
|
};
|
|
75
|
-
var debug = Debug.getInstance();
|
|
76
|
-
var DebugCategory = {
|
|
77
|
-
BROWSER_SDK: "BrowserSDK",
|
|
78
|
-
PROVIDER_MANAGER: "ProviderManager",
|
|
79
|
-
EMBEDDED_PROVIDER: "EmbeddedProvider",
|
|
80
|
-
INJECTED_PROVIDER: "InjectedProvider",
|
|
81
|
-
PHANTOM_CONNECT_AUTH: "PhantomConnectAuth",
|
|
82
|
-
JWT_AUTH: "JWTAuth",
|
|
83
|
-
STORAGE: "Storage",
|
|
84
|
-
SESSION: "Session"
|
|
85
|
-
};
|
|
86
1410
|
|
|
87
1411
|
// src/providers/injected/chains/SolanaChain.ts
|
|
88
|
-
import { EventEmitter } from "eventemitter3";
|
|
89
|
-
import {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
constructor(phantom, callbacks) {
|
|
93
|
-
this._connected = false;
|
|
1412
|
+
import { EventEmitter as EventEmitter3 } from "eventemitter3";
|
|
1413
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
1414
|
+
var PhantomSolanaChain = class {
|
|
1415
|
+
constructor(phantom) {
|
|
94
1416
|
this._publicKey = null;
|
|
95
|
-
this.eventEmitter = new
|
|
1417
|
+
this.eventEmitter = new EventEmitter3();
|
|
96
1418
|
this.phantom = phantom;
|
|
97
|
-
this.callbacks = callbacks;
|
|
98
1419
|
this.setupEventListeners();
|
|
99
|
-
this.syncInitialState();
|
|
100
1420
|
}
|
|
101
1421
|
// Wallet adapter compliant properties
|
|
102
1422
|
get connected() {
|
|
103
|
-
return this.
|
|
1423
|
+
return this._publicKey !== null;
|
|
104
1424
|
}
|
|
105
1425
|
get publicKey() {
|
|
106
1426
|
return this._publicKey;
|
|
107
1427
|
}
|
|
108
|
-
// Connection methods
|
|
109
|
-
connect(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const addresses = this.callbacks.getAddresses();
|
|
114
|
-
const solanaAddress = addresses.find((addr) => addr.addressType === AddressType2.solana);
|
|
115
|
-
if (!solanaAddress) {
|
|
116
|
-
return Promise.reject(new Error("Solana not enabled for this provider"));
|
|
1428
|
+
// Connection methods
|
|
1429
|
+
async connect(options) {
|
|
1430
|
+
const result = await this.phantom.solana.connect(options);
|
|
1431
|
+
if (!result) {
|
|
1432
|
+
throw new Error("Failed to connect to Solana wallet");
|
|
117
1433
|
}
|
|
118
|
-
|
|
119
|
-
|
|
1434
|
+
const publicKey = typeof result === "string" ? result : "";
|
|
1435
|
+
this._publicKey = publicKey;
|
|
1436
|
+
return { publicKey };
|
|
120
1437
|
}
|
|
121
1438
|
async disconnect() {
|
|
122
|
-
await this.
|
|
1439
|
+
await this.phantom.solana.disconnect();
|
|
1440
|
+
this._publicKey = null;
|
|
123
1441
|
}
|
|
124
1442
|
// Standard wallet adapter methods
|
|
125
1443
|
async signMessage(message) {
|
|
126
1444
|
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
127
1445
|
const result = await this.phantom.solana.signMessage(messageBytes);
|
|
128
1446
|
return {
|
|
129
|
-
signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(
|
|
1447
|
+
signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(Buffer3.from(result.signature, "base64")),
|
|
130
1448
|
publicKey: this._publicKey || ""
|
|
131
1449
|
};
|
|
132
1450
|
}
|
|
133
1451
|
async signTransaction(transaction) {
|
|
134
|
-
if (!this.
|
|
1452
|
+
if (!this.connected) {
|
|
135
1453
|
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
136
1454
|
}
|
|
137
1455
|
try {
|
|
@@ -146,7 +1464,7 @@ var InjectedSolanaChain = class {
|
|
|
146
1464
|
return { signature: result.signature };
|
|
147
1465
|
}
|
|
148
1466
|
async signAllTransactions(transactions) {
|
|
149
|
-
if (!this.
|
|
1467
|
+
if (!this.connected) {
|
|
150
1468
|
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
151
1469
|
}
|
|
152
1470
|
try {
|
|
@@ -157,7 +1475,7 @@ var InjectedSolanaChain = class {
|
|
|
157
1475
|
}
|
|
158
1476
|
}
|
|
159
1477
|
async signAndSendAllTransactions(transactions) {
|
|
160
|
-
if (!this.
|
|
1478
|
+
if (!this.connected) {
|
|
161
1479
|
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
162
1480
|
}
|
|
163
1481
|
try {
|
|
@@ -175,42 +1493,21 @@ var InjectedSolanaChain = class {
|
|
|
175
1493
|
return Promise.resolve(this._publicKey);
|
|
176
1494
|
}
|
|
177
1495
|
isConnected() {
|
|
178
|
-
return this.
|
|
1496
|
+
return this.connected;
|
|
179
1497
|
}
|
|
180
1498
|
setupEventListeners() {
|
|
181
1499
|
this.phantom.solana.addEventListener("connect", (publicKey) => {
|
|
182
|
-
this.
|
|
1500
|
+
this._publicKey = publicKey;
|
|
183
1501
|
this.eventEmitter.emit("connect", publicKey);
|
|
184
1502
|
});
|
|
185
1503
|
this.phantom.solana.addEventListener("disconnect", () => {
|
|
186
|
-
this.
|
|
1504
|
+
this._publicKey = null;
|
|
187
1505
|
this.eventEmitter.emit("disconnect");
|
|
188
1506
|
});
|
|
189
1507
|
this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
|
|
190
1508
|
this._publicKey = publicKey;
|
|
191
1509
|
this.eventEmitter.emit("accountChanged", publicKey);
|
|
192
1510
|
});
|
|
193
|
-
this.callbacks.on("connect", (data) => {
|
|
194
|
-
const solanaAddress = data.addresses?.find((addr) => addr.addressType === AddressType2.solana);
|
|
195
|
-
if (solanaAddress) {
|
|
196
|
-
this.updateConnectionState(true, solanaAddress.address);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
this.callbacks.on("disconnect", () => {
|
|
200
|
-
this.updateConnectionState(false, null);
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
syncInitialState() {
|
|
204
|
-
if (this.callbacks.isConnected()) {
|
|
205
|
-
const solanaAddress = this.callbacks.getAddresses().find((addr) => addr.addressType === AddressType2.solana);
|
|
206
|
-
if (solanaAddress) {
|
|
207
|
-
this.updateConnectionState(true, solanaAddress.address);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
updateConnectionState(connected, publicKey) {
|
|
212
|
-
this._connected = connected;
|
|
213
|
-
this._publicKey = publicKey;
|
|
214
1511
|
}
|
|
215
1512
|
// Event methods for interface compliance
|
|
216
1513
|
on(event, listener) {
|
|
@@ -222,22 +1519,18 @@ var InjectedSolanaChain = class {
|
|
|
222
1519
|
};
|
|
223
1520
|
|
|
224
1521
|
// src/providers/injected/chains/EthereumChain.ts
|
|
225
|
-
import { EventEmitter as
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
constructor(phantom, callbacks) {
|
|
229
|
-
this._connected = false;
|
|
1522
|
+
import { EventEmitter as EventEmitter4 } from "eventemitter3";
|
|
1523
|
+
var PhantomEthereumChain = class {
|
|
1524
|
+
constructor(phantom) {
|
|
230
1525
|
this._chainId = "0x1";
|
|
231
1526
|
this._accounts = [];
|
|
232
|
-
this.eventEmitter = new
|
|
1527
|
+
this.eventEmitter = new EventEmitter4();
|
|
233
1528
|
this.phantom = phantom;
|
|
234
|
-
this.callbacks = callbacks;
|
|
235
1529
|
this.setupEventListeners();
|
|
236
|
-
this.syncInitialState();
|
|
237
1530
|
}
|
|
238
1531
|
// EIP-1193 compliant properties
|
|
239
1532
|
get connected() {
|
|
240
|
-
return this.
|
|
1533
|
+
return this._accounts.length > 0;
|
|
241
1534
|
}
|
|
242
1535
|
get chainId() {
|
|
243
1536
|
return this._chainId;
|
|
@@ -252,21 +1545,18 @@ var InjectedEthereumChain = class {
|
|
|
252
1545
|
const result = await this.signTransaction(transaction);
|
|
253
1546
|
return result;
|
|
254
1547
|
}
|
|
255
|
-
const
|
|
256
|
-
return await
|
|
1548
|
+
const phantomProvider = await this.phantom.ethereum.getProvider();
|
|
1549
|
+
return await phantomProvider.request(args);
|
|
257
1550
|
}
|
|
258
|
-
// Connection methods
|
|
259
|
-
connect() {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const addresses = this.callbacks.getAddresses();
|
|
264
|
-
const ethAddresses = addresses.filter((addr) => addr.addressType === AddressType3.ethereum).map((addr) => addr.address);
|
|
265
|
-
this.updateConnectionState(true, ethAddresses);
|
|
266
|
-
return Promise.resolve(ethAddresses);
|
|
1551
|
+
// Connection methods
|
|
1552
|
+
async connect() {
|
|
1553
|
+
const accounts = await this.phantom.ethereum.getAccounts();
|
|
1554
|
+
this._accounts = accounts;
|
|
1555
|
+
return accounts;
|
|
267
1556
|
}
|
|
268
1557
|
async disconnect() {
|
|
269
|
-
await this.
|
|
1558
|
+
await this.phantom.ethereum.disconnect();
|
|
1559
|
+
this._accounts = [];
|
|
270
1560
|
}
|
|
271
1561
|
// Standard compliant methods (return raw values, not wrapped objects)
|
|
272
1562
|
async signPersonalMessage(message, address) {
|
|
@@ -295,16 +1585,16 @@ var InjectedEthereumChain = class {
|
|
|
295
1585
|
return await this.phantom.ethereum.getAccounts();
|
|
296
1586
|
}
|
|
297
1587
|
isConnected() {
|
|
298
|
-
return this.
|
|
1588
|
+
return this.connected;
|
|
299
1589
|
}
|
|
300
1590
|
setupEventListeners() {
|
|
301
1591
|
this.phantom.ethereum.addEventListener("connect", (accounts) => {
|
|
302
|
-
this.
|
|
1592
|
+
this._accounts = accounts;
|
|
303
1593
|
this.eventEmitter.emit("connect", { chainId: this._chainId });
|
|
304
1594
|
this.eventEmitter.emit("accountsChanged", accounts);
|
|
305
1595
|
});
|
|
306
1596
|
this.phantom.ethereum.addEventListener("disconnect", () => {
|
|
307
|
-
this.
|
|
1597
|
+
this._accounts = [];
|
|
308
1598
|
this.eventEmitter.emit("disconnect", { code: 4900, message: "Provider disconnected" });
|
|
309
1599
|
this.eventEmitter.emit("accountsChanged", []);
|
|
310
1600
|
});
|
|
@@ -316,27 +1606,6 @@ var InjectedEthereumChain = class {
|
|
|
316
1606
|
this._chainId = chainId;
|
|
317
1607
|
this.eventEmitter.emit("chainChanged", chainId);
|
|
318
1608
|
});
|
|
319
|
-
this.callbacks.on("connect", (data) => {
|
|
320
|
-
const ethAddresses = data.addresses?.filter((addr) => addr.addressType === AddressType3.ethereum)?.map((addr) => addr.address) || [];
|
|
321
|
-
if (ethAddresses.length > 0) {
|
|
322
|
-
this.updateConnectionState(true, ethAddresses);
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
this.callbacks.on("disconnect", () => {
|
|
326
|
-
this.updateConnectionState(false, []);
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
syncInitialState() {
|
|
330
|
-
if (this.callbacks.isConnected()) {
|
|
331
|
-
const ethAddresses = this.callbacks.getAddresses().filter((addr) => addr.addressType === AddressType3.ethereum).map((addr) => addr.address);
|
|
332
|
-
if (ethAddresses.length > 0) {
|
|
333
|
-
this.updateConnectionState(true, ethAddresses);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
updateConnectionState(connected, accounts) {
|
|
338
|
-
this._connected = connected;
|
|
339
|
-
this._accounts = accounts;
|
|
340
1609
|
}
|
|
341
1610
|
// Event methods for interface compliance
|
|
342
1611
|
on(event, listener) {
|
|
@@ -347,64 +1616,400 @@ var InjectedEthereumChain = class {
|
|
|
347
1616
|
}
|
|
348
1617
|
};
|
|
349
1618
|
|
|
1619
|
+
// src/wallets/registry.ts
|
|
1620
|
+
function isPhantomWallet(wallet) {
|
|
1621
|
+
return wallet !== void 0 && wallet.id === "phantom" && "isPhantom" in wallet && wallet.isPhantom === true;
|
|
1622
|
+
}
|
|
1623
|
+
var InjectedWalletRegistry = class {
|
|
1624
|
+
constructor() {
|
|
1625
|
+
this.wallets = /* @__PURE__ */ new Map();
|
|
1626
|
+
this.discoveryPromise = null;
|
|
1627
|
+
}
|
|
1628
|
+
register(info) {
|
|
1629
|
+
const wrappedProviders = {};
|
|
1630
|
+
if (info.providers?.solana) {
|
|
1631
|
+
const isWalletStandard = info.providers.solana && typeof info.providers.solana === "object" && "features" in info.providers.solana && typeof info.providers.solana.features === "object";
|
|
1632
|
+
if (isWalletStandard) {
|
|
1633
|
+
wrappedProviders.solana = new WalletStandardSolanaAdapter(info.providers.solana, info.id, info.name);
|
|
1634
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wrapped Wallet Standard Solana wallet with adapter", {
|
|
1635
|
+
walletId: info.id,
|
|
1636
|
+
walletName: info.name
|
|
1637
|
+
});
|
|
1638
|
+
} else {
|
|
1639
|
+
wrappedProviders.solana = new InjectedWalletSolanaChain(info.providers.solana, info.id, info.name);
|
|
1640
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wrapped Solana provider with InjectedWalletSolanaChain", {
|
|
1641
|
+
walletId: info.id,
|
|
1642
|
+
walletName: info.name
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
if (info.providers?.ethereum) {
|
|
1647
|
+
wrappedProviders.ethereum = new InjectedWalletEthereumChain(info.providers.ethereum, info.id, info.name);
|
|
1648
|
+
debug.log(DebugCategory.BROWSER_SDK, "Wrapped Ethereum provider with InjectedWalletEthereumChain", {
|
|
1649
|
+
walletId: info.id,
|
|
1650
|
+
walletName: info.name
|
|
1651
|
+
});
|
|
1652
|
+
}
|
|
1653
|
+
const wrappedInfo = {
|
|
1654
|
+
...info,
|
|
1655
|
+
providers: Object.keys(wrappedProviders).length > 0 ? wrappedProviders : info.providers
|
|
1656
|
+
};
|
|
1657
|
+
this.wallets.set(info.id, wrappedInfo);
|
|
1658
|
+
}
|
|
1659
|
+
/**
|
|
1660
|
+
* Register Phantom wallet with its instance
|
|
1661
|
+
* This creates wrapped providers and stores the Phantom instance for auto-confirm access
|
|
1662
|
+
*/
|
|
1663
|
+
registerPhantom(phantomInstance, addressTypes, icon) {
|
|
1664
|
+
const wrappedProviders = {};
|
|
1665
|
+
if (addressTypes.includes(AddressType.solana) && phantomInstance.solana) {
|
|
1666
|
+
wrappedProviders.solana = new PhantomSolanaChain(phantomInstance);
|
|
1667
|
+
debug.log(DebugCategory.BROWSER_SDK, "Created PhantomSolanaChain wrapper", {
|
|
1668
|
+
walletId: "phantom"
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
if (addressTypes.includes(AddressType.ethereum) && phantomInstance.ethereum) {
|
|
1672
|
+
wrappedProviders.ethereum = new PhantomEthereumChain(phantomInstance);
|
|
1673
|
+
debug.log(DebugCategory.BROWSER_SDK, "Created PhantomEthereumChain wrapper", {
|
|
1674
|
+
walletId: "phantom"
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1677
|
+
const phantomWallet = {
|
|
1678
|
+
id: "phantom",
|
|
1679
|
+
name: "Phantom",
|
|
1680
|
+
icon: icon || "https://phantom.app/img/phantom-icon-purple.png",
|
|
1681
|
+
addressTypes,
|
|
1682
|
+
providers: wrappedProviders,
|
|
1683
|
+
isPhantom: true,
|
|
1684
|
+
phantomInstance
|
|
1685
|
+
};
|
|
1686
|
+
this.wallets.set("phantom", phantomWallet);
|
|
1687
|
+
debug.log(DebugCategory.BROWSER_SDK, "Registered Phantom wallet with chain wrappers", {
|
|
1688
|
+
addressTypes,
|
|
1689
|
+
hasSolana: !!wrappedProviders.solana,
|
|
1690
|
+
hasEthereum: !!wrappedProviders.ethereum
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
unregister(id) {
|
|
1694
|
+
this.wallets.delete(id);
|
|
1695
|
+
}
|
|
1696
|
+
has(id) {
|
|
1697
|
+
return this.wallets.has(id);
|
|
1698
|
+
}
|
|
1699
|
+
getById(id) {
|
|
1700
|
+
return this.wallets.get(id);
|
|
1701
|
+
}
|
|
1702
|
+
getAll() {
|
|
1703
|
+
return Array.from(this.wallets.values());
|
|
1704
|
+
}
|
|
1705
|
+
getByAddressTypes(addressTypes) {
|
|
1706
|
+
if (addressTypes.length === 0) {
|
|
1707
|
+
return this.getAll();
|
|
1708
|
+
}
|
|
1709
|
+
const allowed = new Set(addressTypes);
|
|
1710
|
+
return this.getAll().filter((wallet) => wallet.addressTypes.some((t) => allowed.has(t)));
|
|
1711
|
+
}
|
|
1712
|
+
discover(addressTypes) {
|
|
1713
|
+
if (this.discoveryPromise) {
|
|
1714
|
+
return this.discoveryPromise;
|
|
1715
|
+
}
|
|
1716
|
+
debug.log(DebugCategory.BROWSER_SDK, "Starting wallet discovery", { addressTypes });
|
|
1717
|
+
this.discoveryPromise = discoverWallets(addressTypes).then((discoveredWallets) => {
|
|
1718
|
+
const relevantWallets = addressTypes ? discoveredWallets.filter((wallet) => wallet.addressTypes.some((type) => addressTypes.includes(type))) : discoveredWallets;
|
|
1719
|
+
for (const wallet of relevantWallets) {
|
|
1720
|
+
if (wallet.id === "phantom" && isPhantomWallet(wallet)) {
|
|
1721
|
+
this.registerPhantom(wallet.phantomInstance, wallet.addressTypes, wallet.icon);
|
|
1722
|
+
} else {
|
|
1723
|
+
this.register(wallet);
|
|
1724
|
+
}
|
|
1725
|
+
debug.log(DebugCategory.BROWSER_SDK, "Registered discovered wallet", {
|
|
1726
|
+
id: wallet.id,
|
|
1727
|
+
name: wallet.name,
|
|
1728
|
+
addressTypes: wallet.addressTypes
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
debug.info(DebugCategory.BROWSER_SDK, "Wallet discovery completed", {
|
|
1732
|
+
totalDiscovered: discoveredWallets.length,
|
|
1733
|
+
relevantWallets: relevantWallets.length
|
|
1734
|
+
});
|
|
1735
|
+
}).catch((error) => {
|
|
1736
|
+
debug.warn(DebugCategory.BROWSER_SDK, "Wallet discovery failed", { error });
|
|
1737
|
+
this.discoveryPromise = null;
|
|
1738
|
+
throw error;
|
|
1739
|
+
});
|
|
1740
|
+
return this.discoveryPromise;
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
var walletRegistry = null;
|
|
1744
|
+
function getWalletRegistry() {
|
|
1745
|
+
if (!walletRegistry) {
|
|
1746
|
+
walletRegistry = new InjectedWalletRegistry();
|
|
1747
|
+
}
|
|
1748
|
+
return walletRegistry;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
350
1751
|
// src/providers/injected/index.ts
|
|
351
1752
|
var WAS_CONNECTED_KEY = "phantom-injected-was-connected";
|
|
352
1753
|
var WAS_CONNECTED_VALUE = "true";
|
|
1754
|
+
var LAST_WALLET_ID_KEY = "phantom-injected-last-wallet-id";
|
|
353
1755
|
var InjectedProvider = class {
|
|
1756
|
+
// Track which wallets have event listeners set up
|
|
354
1757
|
constructor(config) {
|
|
355
|
-
this.
|
|
356
|
-
this.
|
|
1758
|
+
this.selectedWalletId = null;
|
|
1759
|
+
this.walletStates = /* @__PURE__ */ new Map();
|
|
357
1760
|
// Event management
|
|
358
1761
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
359
1762
|
this.browserInjectedCleanupFunctions = [];
|
|
360
1763
|
this.eventsInitialized = false;
|
|
1764
|
+
this.externalWalletEventListenersSetup = /* @__PURE__ */ new Set();
|
|
361
1765
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Initializing InjectedProvider", { config });
|
|
362
1766
|
this.addressTypes = config.addressTypes;
|
|
1767
|
+
this.walletRegistry = getWalletRegistry();
|
|
363
1768
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
plugins.push(createSolanaPlugin());
|
|
367
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana plugin added");
|
|
368
|
-
}
|
|
369
|
-
if (this.addressTypes.includes(AddressType4.ethereum)) {
|
|
370
|
-
plugins.push(createEthereumPlugin());
|
|
371
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum plugin added");
|
|
372
|
-
}
|
|
373
|
-
plugins.push(createAutoConfirmPlugin());
|
|
374
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "AutoConfirm plugin added");
|
|
375
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Creating Phantom instance with plugins", {
|
|
376
|
-
pluginCount: plugins.length
|
|
1769
|
+
this.walletRegistry.discover(this.addressTypes).catch((error) => {
|
|
1770
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Wallet discovery failed during initialization", { error });
|
|
377
1771
|
});
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
1772
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "InjectedProvider initialized");
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Wait for wallet discovery to complete if the wallet is not yet in the registry
|
|
1776
|
+
* This is needed for auto-connect when the last wallet was an external wallet
|
|
1777
|
+
*/
|
|
1778
|
+
async waitForWalletDiscovery(walletId) {
|
|
1779
|
+
if (this.walletRegistry.has(walletId)) {
|
|
1780
|
+
return;
|
|
382
1781
|
}
|
|
383
|
-
|
|
384
|
-
|
|
1782
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet not found in registry, waiting for discovery", {
|
|
1783
|
+
walletId
|
|
1784
|
+
});
|
|
1785
|
+
try {
|
|
1786
|
+
await this.walletRegistry.discover(this.addressTypes);
|
|
1787
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Wallet discovery completed", { walletId });
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Wallet discovery failed", {
|
|
1790
|
+
walletId,
|
|
1791
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1792
|
+
});
|
|
385
1793
|
}
|
|
386
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "InjectedProvider initialized");
|
|
387
1794
|
}
|
|
388
1795
|
get solana() {
|
|
389
|
-
if (!this.addressTypes.includes(
|
|
1796
|
+
if (!this.addressTypes.includes(AddressType2.solana)) {
|
|
390
1797
|
throw new Error("Solana not enabled for this provider");
|
|
391
1798
|
}
|
|
392
|
-
|
|
393
|
-
|
|
1799
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
1800
|
+
const walletInfo = this.walletRegistry.getById(walletId);
|
|
1801
|
+
if (!walletInfo) {
|
|
1802
|
+
const registry = this.walletRegistry;
|
|
1803
|
+
if (registry.discoveryPromise) {
|
|
1804
|
+
throw new Error(
|
|
1805
|
+
`Wallet "${walletId}" not found. Wallet discovery is still in progress. Please wait for sdk.discoverWallets() to complete before accessing chain properties.`
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
throw new Error(
|
|
1809
|
+
`Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
if (!walletInfo.providers?.solana) {
|
|
1813
|
+
throw new Error(
|
|
1814
|
+
`Selected wallet "${walletInfo.name}" does not support Solana. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Solana in addressTypes.`
|
|
1815
|
+
);
|
|
1816
|
+
}
|
|
1817
|
+
return walletInfo.providers.solana;
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Access to Ethereum chain operations
|
|
1821
|
+
*/
|
|
1822
|
+
get ethereum() {
|
|
1823
|
+
if (!this.addressTypes.includes(AddressType2.ethereum)) {
|
|
1824
|
+
throw new Error("Ethereum not enabled for this provider");
|
|
1825
|
+
}
|
|
1826
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
1827
|
+
const walletInfo = this.walletRegistry.getById(walletId);
|
|
1828
|
+
if (!walletInfo) {
|
|
1829
|
+
const registry = this.walletRegistry;
|
|
1830
|
+
if (registry.discoveryPromise) {
|
|
1831
|
+
throw new Error(
|
|
1832
|
+
`Wallet "${walletId}" not found. Wallet discovery is still in progress. Please wait for sdk.discoverWallets() to complete before accessing chain properties.`
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
throw new Error(
|
|
1836
|
+
`Wallet "${walletId}" not found. Please ensure wallet discovery has completed. Make sure you call sdk.discoverWallets() and await it before accessing chain properties.`
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
if (!walletInfo.providers?.ethereum) {
|
|
1840
|
+
throw new Error(
|
|
1841
|
+
`Selected wallet "${walletInfo.name}" does not support Ethereum. This wallet only supports: ${walletInfo.addressTypes.join(", ")}. Make sure your SDK config includes Ethereum in addressTypes.`
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
return walletInfo.providers.ethereum;
|
|
1845
|
+
}
|
|
1846
|
+
validateAndSelectWallet(requestedWalletId) {
|
|
1847
|
+
if (!this.walletRegistry.has(requestedWalletId)) {
|
|
1848
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Unknown injected wallet id requested", {
|
|
1849
|
+
walletId: requestedWalletId
|
|
1850
|
+
});
|
|
1851
|
+
throw new Error(`Unknown injected wallet id: ${requestedWalletId}`);
|
|
1852
|
+
}
|
|
1853
|
+
const walletInfo = this.walletRegistry.getById(requestedWalletId);
|
|
1854
|
+
if (!walletInfo || !walletInfo.providers) {
|
|
1855
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Wallet not available for connection", {
|
|
1856
|
+
walletId: requestedWalletId
|
|
1857
|
+
});
|
|
1858
|
+
throw new Error(`Wallet not available for connection: ${requestedWalletId}`);
|
|
1859
|
+
}
|
|
1860
|
+
this.selectedWalletId = requestedWalletId;
|
|
1861
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Selected injected wallet for connection", {
|
|
1862
|
+
walletId: requestedWalletId
|
|
1863
|
+
});
|
|
1864
|
+
return walletInfo;
|
|
1865
|
+
}
|
|
1866
|
+
async connectToWallet(walletInfo, options) {
|
|
1867
|
+
if (!walletInfo.providers) {
|
|
1868
|
+
const error = new Error(`Wallet adapter not available for wallet: ${this.selectedWalletId}`);
|
|
1869
|
+
debug.error(DebugCategory.INJECTED_PROVIDER, "Wallet adapter not available", { walletId: this.selectedWalletId });
|
|
1870
|
+
this.emit("connect_error", {
|
|
1871
|
+
error: error.message,
|
|
1872
|
+
source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
|
|
1873
|
+
});
|
|
1874
|
+
throw error;
|
|
1875
|
+
}
|
|
1876
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Connecting via wallet", {
|
|
1877
|
+
walletId: this.selectedWalletId,
|
|
1878
|
+
walletName: walletInfo.name,
|
|
1879
|
+
options
|
|
1880
|
+
});
|
|
1881
|
+
if (!options?.skipEventListeners) {
|
|
1882
|
+
this.setupExternalWalletEvents(walletInfo);
|
|
1883
|
+
if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
|
|
1884
|
+
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
1885
|
+
this.browserInjectedCleanupFunctions = [];
|
|
1886
|
+
this.setupBrowserInjectedEvents();
|
|
1887
|
+
this.eventsInitialized = true;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
const connectedAddresses = [];
|
|
1891
|
+
if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers?.solana) {
|
|
1892
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection", {
|
|
1893
|
+
walletId: this.selectedWalletId,
|
|
1894
|
+
walletName: walletInfo.name,
|
|
1895
|
+
onlyIfTrusted: options?.onlyIfTrusted
|
|
1896
|
+
});
|
|
1897
|
+
try {
|
|
1898
|
+
const result = await walletInfo.providers.solana.connect(
|
|
1899
|
+
options?.onlyIfTrusted ? { onlyIfTrusted: true } : void 0
|
|
1900
|
+
);
|
|
1901
|
+
const address = result.publicKey;
|
|
1902
|
+
connectedAddresses.push({
|
|
1903
|
+
addressType: AddressType2.solana,
|
|
1904
|
+
address
|
|
1905
|
+
});
|
|
1906
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", {
|
|
1907
|
+
address,
|
|
1908
|
+
walletId: this.selectedWalletId,
|
|
1909
|
+
walletName: walletInfo.name
|
|
1910
|
+
});
|
|
1911
|
+
} catch (err) {
|
|
1912
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", {
|
|
1913
|
+
error: err,
|
|
1914
|
+
walletId: this.selectedWalletId,
|
|
1915
|
+
walletName: walletInfo.name
|
|
1916
|
+
});
|
|
1917
|
+
this.emit("connect_error", {
|
|
1918
|
+
error: err instanceof Error ? err.message : "Failed to connect",
|
|
1919
|
+
source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
|
|
1920
|
+
});
|
|
1921
|
+
throw err;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers?.ethereum) {
|
|
1925
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum connection", {
|
|
1926
|
+
walletId: this.selectedWalletId,
|
|
1927
|
+
walletName: walletInfo.name,
|
|
1928
|
+
silent: options?.silent
|
|
1929
|
+
});
|
|
1930
|
+
try {
|
|
1931
|
+
let accounts;
|
|
1932
|
+
if (options?.silent) {
|
|
1933
|
+
accounts = await walletInfo.providers.ethereum.request({ method: "eth_accounts" });
|
|
1934
|
+
} else {
|
|
1935
|
+
accounts = await walletInfo.providers.ethereum.connect();
|
|
1936
|
+
}
|
|
1937
|
+
if (accounts.length > 0) {
|
|
1938
|
+
connectedAddresses.push(
|
|
1939
|
+
...accounts.map((address) => ({
|
|
1940
|
+
addressType: AddressType2.ethereum,
|
|
1941
|
+
address
|
|
1942
|
+
}))
|
|
1943
|
+
);
|
|
1944
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum connected successfully", {
|
|
1945
|
+
addresses: accounts,
|
|
1946
|
+
walletId: this.selectedWalletId,
|
|
1947
|
+
walletName: walletInfo.name
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
} catch (err) {
|
|
1951
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", {
|
|
1952
|
+
error: err,
|
|
1953
|
+
walletId: this.selectedWalletId,
|
|
1954
|
+
walletName: walletInfo.name
|
|
1955
|
+
});
|
|
1956
|
+
this.emit("connect_error", {
|
|
1957
|
+
error: err instanceof Error ? err.message : "Failed to connect",
|
|
1958
|
+
source: options?.skipEventListeners ? "auto-connect" : "manual-connect"
|
|
1959
|
+
});
|
|
1960
|
+
throw err;
|
|
1961
|
+
}
|
|
394
1962
|
}
|
|
395
|
-
return
|
|
1963
|
+
return connectedAddresses;
|
|
396
1964
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
1965
|
+
async finalizeConnection(connectedAddresses, authProvider, walletId) {
|
|
1966
|
+
if (connectedAddresses.length === 0) {
|
|
1967
|
+
const error = new Error("Failed to connect to any supported wallet provider");
|
|
1968
|
+
this.emit("connect_error", {
|
|
1969
|
+
error: error.message,
|
|
1970
|
+
source: "manual-connect"
|
|
1971
|
+
});
|
|
1972
|
+
throw error;
|
|
403
1973
|
}
|
|
404
|
-
if (
|
|
405
|
-
|
|
1974
|
+
if (this.selectedWalletId) {
|
|
1975
|
+
this.setWalletState(this.selectedWalletId, {
|
|
1976
|
+
connected: true,
|
|
1977
|
+
addresses: connectedAddresses
|
|
1978
|
+
});
|
|
406
1979
|
}
|
|
407
|
-
|
|
1980
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Finalized connection with addresses", {
|
|
1981
|
+
addressCount: connectedAddresses.length,
|
|
1982
|
+
addresses: connectedAddresses.map((addr) => ({
|
|
1983
|
+
type: addr.addressType,
|
|
1984
|
+
address: addr.address.substring(0, 10) + "..."
|
|
1985
|
+
}))
|
|
1986
|
+
});
|
|
1987
|
+
const authUserId = await this.getAuthUserId("manual-connect");
|
|
1988
|
+
try {
|
|
1989
|
+
localStorage.setItem(WAS_CONNECTED_KEY, WAS_CONNECTED_VALUE);
|
|
1990
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Set was-connected flag - auto-reconnect enabled");
|
|
1991
|
+
if (this.selectedWalletId) {
|
|
1992
|
+
localStorage.setItem(LAST_WALLET_ID_KEY, this.selectedWalletId);
|
|
1993
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Stored last injected wallet id", {
|
|
1994
|
+
walletId: this.selectedWalletId
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
} catch (error) {
|
|
1998
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to persist injected provider state", { error });
|
|
1999
|
+
}
|
|
2000
|
+
const result = {
|
|
2001
|
+
addresses: connectedAddresses,
|
|
2002
|
+
status: "completed",
|
|
2003
|
+
authUserId,
|
|
2004
|
+
authProvider,
|
|
2005
|
+
walletId
|
|
2006
|
+
};
|
|
2007
|
+
this.emit("connect", {
|
|
2008
|
+
addresses: connectedAddresses,
|
|
2009
|
+
source: "manual-connect",
|
|
2010
|
+
authUserId
|
|
2011
|
+
});
|
|
2012
|
+
return result;
|
|
408
2013
|
}
|
|
409
2014
|
async connect(authOptions) {
|
|
410
2015
|
debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider connect", {
|
|
@@ -419,110 +2024,48 @@ var InjectedProvider = class {
|
|
|
419
2024
|
providerType: "injected"
|
|
420
2025
|
});
|
|
421
2026
|
try {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
2027
|
+
const requestedWalletId = authOptions.walletId || "phantom";
|
|
2028
|
+
const walletInfo = this.validateAndSelectWallet(requestedWalletId);
|
|
2029
|
+
const connectedAddresses = await this.connectToWallet(walletInfo);
|
|
2030
|
+
return await this.finalizeConnection(connectedAddresses, "injected", this.selectedWalletId || void 0);
|
|
2031
|
+
} catch (error) {
|
|
2032
|
+
this.emit("connect_error", {
|
|
2033
|
+
error: error instanceof Error ? error.message : "Failed to connect",
|
|
2034
|
+
source: "manual-connect"
|
|
2035
|
+
});
|
|
2036
|
+
throw error;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
async disconnect() {
|
|
2040
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
|
|
2041
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2042
|
+
if (walletInfo?.providers) {
|
|
2043
|
+
if (this.addressTypes.includes(AddressType2.solana) && walletInfo.providers.solana) {
|
|
435
2044
|
try {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
connectedAddresses.push({
|
|
439
|
-
addressType: AddressType4.solana,
|
|
440
|
-
address: publicKey
|
|
441
|
-
});
|
|
442
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
|
|
443
|
-
}
|
|
2045
|
+
await walletInfo.providers.solana.disconnect();
|
|
2046
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
|
|
444
2047
|
} catch (err) {
|
|
445
|
-
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to
|
|
446
|
-
this.emit("connect_error", {
|
|
447
|
-
error: err instanceof Error ? err.message : "Failed to connect",
|
|
448
|
-
source: "manual-connect"
|
|
449
|
-
});
|
|
450
|
-
throw err;
|
|
2048
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
|
|
451
2049
|
}
|
|
452
2050
|
}
|
|
453
|
-
if (this.addressTypes.includes(
|
|
2051
|
+
if (this.addressTypes.includes(AddressType2.ethereum) && walletInfo.providers.ethereum) {
|
|
454
2052
|
try {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
connectedAddresses.push(
|
|
458
|
-
...accounts.map((address) => ({
|
|
459
|
-
addressType: AddressType4.ethereum,
|
|
460
|
-
address
|
|
461
|
-
}))
|
|
462
|
-
);
|
|
463
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum connected successfully", { addresses: accounts });
|
|
464
|
-
}
|
|
2053
|
+
await walletInfo.providers.ethereum.disconnect();
|
|
2054
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected successfully");
|
|
465
2055
|
} catch (err) {
|
|
466
|
-
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to
|
|
467
|
-
this.emit("connect_error", {
|
|
468
|
-
error: err instanceof Error ? err.message : "Failed to connect",
|
|
469
|
-
source: "manual-connect"
|
|
470
|
-
});
|
|
471
|
-
throw err;
|
|
2056
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Ethereum", { error: err });
|
|
472
2057
|
}
|
|
473
2058
|
}
|
|
474
|
-
if (connectedAddresses.length === 0) {
|
|
475
|
-
const error = new Error("Failed to connect to any supported wallet provider");
|
|
476
|
-
this.emit("connect_error", {
|
|
477
|
-
error: error.message,
|
|
478
|
-
source: "manual-connect"
|
|
479
|
-
});
|
|
480
|
-
throw error;
|
|
481
|
-
}
|
|
482
|
-
this.addresses = connectedAddresses;
|
|
483
|
-
this.connected = true;
|
|
484
|
-
const authUserId = await this.getAuthUserId("manual-connect");
|
|
485
|
-
try {
|
|
486
|
-
localStorage.setItem(WAS_CONNECTED_KEY, WAS_CONNECTED_VALUE);
|
|
487
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Set was-connected flag - auto-reconnect enabled");
|
|
488
|
-
} catch (error) {
|
|
489
|
-
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to set was-connected flag", { error });
|
|
490
|
-
}
|
|
491
|
-
const result = {
|
|
492
|
-
addresses: this.addresses,
|
|
493
|
-
status: "completed",
|
|
494
|
-
authUserId
|
|
495
|
-
};
|
|
496
|
-
this.emit("connect", {
|
|
497
|
-
addresses: this.addresses,
|
|
498
|
-
source: "manual-connect",
|
|
499
|
-
authUserId
|
|
500
|
-
});
|
|
501
|
-
return result;
|
|
502
|
-
} catch (error) {
|
|
503
|
-
if (error instanceof Error && !error.message.includes("Phantom wallet not found") && !error.message.includes("Failed to connect to any supported wallet provider")) {
|
|
504
|
-
this.emit("connect_error", {
|
|
505
|
-
error: error.message,
|
|
506
|
-
source: "manual-connect"
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
throw error;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
async disconnect() {
|
|
513
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
|
|
514
|
-
if (this.addressTypes.includes(AddressType4.solana)) {
|
|
515
|
-
try {
|
|
516
|
-
await this.phantom.solana.disconnect();
|
|
517
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
|
|
518
|
-
} catch (err) {
|
|
519
|
-
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
|
|
520
|
-
}
|
|
521
2059
|
}
|
|
522
2060
|
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
523
2061
|
this.browserInjectedCleanupFunctions = [];
|
|
524
|
-
this.
|
|
525
|
-
|
|
2062
|
+
if (this.selectedWalletId) {
|
|
2063
|
+
this.externalWalletEventListenersSetup.delete(this.selectedWalletId);
|
|
2064
|
+
this.setWalletState(this.selectedWalletId, {
|
|
2065
|
+
connected: false,
|
|
2066
|
+
addresses: []
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
526
2069
|
try {
|
|
527
2070
|
localStorage.removeItem(WAS_CONNECTED_KEY);
|
|
528
2071
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Cleared was connected flag to prevent auto-reconnect");
|
|
@@ -541,13 +2084,17 @@ var InjectedProvider = class {
|
|
|
541
2084
|
*/
|
|
542
2085
|
async autoConnect() {
|
|
543
2086
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting auto-connect");
|
|
2087
|
+
let lastWalletId = null;
|
|
544
2088
|
try {
|
|
545
2089
|
const wasConnected = localStorage.getItem(WAS_CONNECTED_KEY);
|
|
546
2090
|
if (wasConnected !== WAS_CONNECTED_VALUE) {
|
|
547
2091
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Skipping auto-connect: user was not previously connected");
|
|
548
2092
|
return;
|
|
549
2093
|
}
|
|
550
|
-
|
|
2094
|
+
lastWalletId = localStorage.getItem(LAST_WALLET_ID_KEY);
|
|
2095
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "User was previously connected, attempting auto-connect", {
|
|
2096
|
+
lastWalletId: lastWalletId || "phantom"
|
|
2097
|
+
});
|
|
551
2098
|
} catch (error) {
|
|
552
2099
|
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to check was-connected flag", { error });
|
|
553
2100
|
return;
|
|
@@ -557,53 +2104,22 @@ var InjectedProvider = class {
|
|
|
557
2104
|
providerType: "injected"
|
|
558
2105
|
});
|
|
559
2106
|
try {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
2107
|
+
const walletId = lastWalletId || "phantom";
|
|
2108
|
+
await this.waitForWalletDiscovery(walletId);
|
|
2109
|
+
const walletInfo = this.validateAndSelectWallet(walletId);
|
|
2110
|
+
let connectedAddresses = [];
|
|
2111
|
+
try {
|
|
2112
|
+
connectedAddresses = await this.connectToWallet(walletInfo, {
|
|
2113
|
+
onlyIfTrusted: true,
|
|
2114
|
+
silent: true,
|
|
2115
|
+
skipEventListeners: true
|
|
2116
|
+
// Set up listeners only if connection succeeds
|
|
2117
|
+
});
|
|
2118
|
+
} catch (err) {
|
|
2119
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed (expected if not trusted)", {
|
|
2120
|
+
error: err,
|
|
2121
|
+
walletId: this.selectedWalletId
|
|
565
2122
|
});
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
const connectedAddresses = [];
|
|
569
|
-
if (this.addressTypes.includes(AddressType4.solana)) {
|
|
570
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana auto-connect");
|
|
571
|
-
try {
|
|
572
|
-
const publicKey = await this.phantom.solana.connect({ onlyIfTrusted: true });
|
|
573
|
-
if (publicKey) {
|
|
574
|
-
connectedAddresses.push({
|
|
575
|
-
addressType: AddressType4.solana,
|
|
576
|
-
address: publicKey
|
|
577
|
-
});
|
|
578
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana auto-connected successfully", { address: publicKey });
|
|
579
|
-
}
|
|
580
|
-
} catch (err) {
|
|
581
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana auto-connect failed (expected if not trusted)", {
|
|
582
|
-
error: err
|
|
583
|
-
});
|
|
584
|
-
throw err;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
if (this.addressTypes.includes(AddressType4.ethereum)) {
|
|
588
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum auto-connect");
|
|
589
|
-
try {
|
|
590
|
-
const accounts = await this.phantom.ethereum.connect({ onlyIfTrusted: true });
|
|
591
|
-
if (accounts && accounts.length > 0) {
|
|
592
|
-
connectedAddresses.push(
|
|
593
|
-
...accounts.map((address) => ({
|
|
594
|
-
addressType: AddressType4.ethereum,
|
|
595
|
-
address
|
|
596
|
-
}))
|
|
597
|
-
);
|
|
598
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connected successfully", {
|
|
599
|
-
addresses: accounts
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
} catch (err) {
|
|
603
|
-
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connect failed (expected if not trusted)", {
|
|
604
|
-
error: err
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
2123
|
}
|
|
608
2124
|
if (connectedAddresses.length === 0) {
|
|
609
2125
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed: no trusted connections available");
|
|
@@ -613,11 +2129,22 @@ var InjectedProvider = class {
|
|
|
613
2129
|
});
|
|
614
2130
|
return;
|
|
615
2131
|
}
|
|
616
|
-
this.
|
|
617
|
-
this.
|
|
2132
|
+
this.setupExternalWalletEvents(walletInfo);
|
|
2133
|
+
if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
|
|
2134
|
+
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
2135
|
+
this.browserInjectedCleanupFunctions = [];
|
|
2136
|
+
this.setupBrowserInjectedEvents();
|
|
2137
|
+
this.eventsInitialized = true;
|
|
2138
|
+
}
|
|
2139
|
+
if (this.selectedWalletId) {
|
|
2140
|
+
this.setWalletState(this.selectedWalletId, {
|
|
2141
|
+
connected: true,
|
|
2142
|
+
addresses: connectedAddresses
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
618
2145
|
const authUserId = await this.getAuthUserId("auto-connect");
|
|
619
2146
|
this.emit("connect", {
|
|
620
|
-
addresses:
|
|
2147
|
+
addresses: connectedAddresses,
|
|
621
2148
|
source: "auto-connect",
|
|
622
2149
|
authUserId
|
|
623
2150
|
});
|
|
@@ -627,6 +2154,7 @@ var InjectedProvider = class {
|
|
|
627
2154
|
type: addr.addressType,
|
|
628
2155
|
address: addr.address.substring(0, 8) + "..."
|
|
629
2156
|
})),
|
|
2157
|
+
walletId: this.selectedWalletId,
|
|
630
2158
|
authUserId
|
|
631
2159
|
});
|
|
632
2160
|
} catch (error) {
|
|
@@ -639,34 +2167,80 @@ var InjectedProvider = class {
|
|
|
639
2167
|
});
|
|
640
2168
|
}
|
|
641
2169
|
}
|
|
2170
|
+
getWalletState(walletId) {
|
|
2171
|
+
if (!this.walletStates.has(walletId)) {
|
|
2172
|
+
this.walletStates.set(walletId, { connected: false, addresses: [] });
|
|
2173
|
+
}
|
|
2174
|
+
return this.walletStates.get(walletId);
|
|
2175
|
+
}
|
|
2176
|
+
setWalletState(walletId, state) {
|
|
2177
|
+
this.walletStates.set(walletId, state);
|
|
2178
|
+
}
|
|
642
2179
|
getAddresses() {
|
|
643
|
-
|
|
2180
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2181
|
+
return this.getWalletState(walletId).addresses;
|
|
2182
|
+
}
|
|
2183
|
+
/**
|
|
2184
|
+
* Get enabled address types for the current selected wallet
|
|
2185
|
+
* - For Phantom: returns config.addressTypes
|
|
2186
|
+
* - For external wallets: returns the wallet's addressTypes from registry
|
|
2187
|
+
*/
|
|
2188
|
+
getEnabledAddressTypes() {
|
|
2189
|
+
if (!this.selectedWalletId || this.selectedWalletId === "phantom") {
|
|
2190
|
+
return this.addressTypes;
|
|
2191
|
+
}
|
|
2192
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId);
|
|
2193
|
+
if (walletInfo) {
|
|
2194
|
+
return walletInfo.addressTypes;
|
|
2195
|
+
}
|
|
2196
|
+
return this.addressTypes;
|
|
644
2197
|
}
|
|
645
2198
|
isConnected() {
|
|
646
|
-
|
|
2199
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2200
|
+
return this.getWalletState(walletId).connected;
|
|
647
2201
|
}
|
|
648
|
-
// AutoConfirm methods - only available for
|
|
2202
|
+
// AutoConfirm methods - only available for Phantom wallet
|
|
649
2203
|
async enableAutoConfirm(params) {
|
|
2204
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2205
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2206
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2207
|
+
}
|
|
650
2208
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Enabling autoConfirm", { params });
|
|
651
|
-
return await
|
|
2209
|
+
return await walletInfo.phantomInstance.autoConfirm.autoConfirmEnable(params);
|
|
652
2210
|
}
|
|
653
2211
|
async disableAutoConfirm() {
|
|
2212
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2213
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2214
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2215
|
+
}
|
|
654
2216
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Disabling autoConfirm");
|
|
655
|
-
await
|
|
2217
|
+
await walletInfo.phantomInstance.autoConfirm.autoConfirmDisable();
|
|
656
2218
|
}
|
|
657
2219
|
async getAutoConfirmStatus() {
|
|
2220
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2221
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2222
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2223
|
+
}
|
|
658
2224
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Getting autoConfirm status");
|
|
659
|
-
return await
|
|
2225
|
+
return await walletInfo.phantomInstance.autoConfirm.autoConfirmStatus();
|
|
660
2226
|
}
|
|
661
2227
|
async getSupportedAutoConfirmChains() {
|
|
2228
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2229
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2230
|
+
throw new Error("Auto-confirm is only available for Phantom wallet");
|
|
2231
|
+
}
|
|
662
2232
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Getting supported autoConfirm chains");
|
|
663
|
-
return await
|
|
2233
|
+
return await walletInfo.phantomInstance.autoConfirm.autoConfirmSupportedChains();
|
|
664
2234
|
}
|
|
665
2235
|
/**
|
|
666
2236
|
* Helper method to get authUserId from window.phantom.app.getUser()
|
|
667
|
-
* Returns undefined if the method is not available or fails
|
|
2237
|
+
* Returns undefined if the method is not available or fails, or if wallet is not Phantom
|
|
668
2238
|
*/
|
|
669
2239
|
async getAuthUserId(context) {
|
|
2240
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2241
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2242
|
+
return void 0;
|
|
2243
|
+
}
|
|
670
2244
|
try {
|
|
671
2245
|
if (window.phantom?.app?.getUser) {
|
|
672
2246
|
const userInfo = await window.phantom.app.getUser();
|
|
@@ -730,140 +2304,245 @@ var InjectedProvider = class {
|
|
|
730
2304
|
}
|
|
731
2305
|
}
|
|
732
2306
|
setupBrowserInjectedEvents() {
|
|
733
|
-
|
|
734
|
-
if (
|
|
735
|
-
|
|
2307
|
+
const walletInfo = this.walletRegistry.getById(this.selectedWalletId || "phantom");
|
|
2308
|
+
if (!isPhantomWallet(walletInfo)) {
|
|
2309
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Skipping browser-injected-sdk event setup - not Phantom wallet");
|
|
2310
|
+
return;
|
|
736
2311
|
}
|
|
737
|
-
|
|
738
|
-
|
|
2312
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
|
|
2313
|
+
if (this.selectedWalletId === "phantom" && isPhantomWallet(walletInfo)) {
|
|
2314
|
+
if (this.addressTypes.includes(AddressType2.solana)) {
|
|
2315
|
+
this.setupSolanaEvents(walletInfo.phantomInstance);
|
|
2316
|
+
}
|
|
2317
|
+
if (this.addressTypes.includes(AddressType2.ethereum)) {
|
|
2318
|
+
this.setupEthereumEvents(walletInfo.phantomInstance);
|
|
2319
|
+
}
|
|
739
2320
|
}
|
|
740
2321
|
}
|
|
741
|
-
setupSolanaEvents() {
|
|
2322
|
+
setupSolanaEvents(phantom) {
|
|
742
2323
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
|
|
743
2324
|
const handleSolanaConnect = async (publicKey) => {
|
|
744
2325
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
2326
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2327
|
+
const state = this.getWalletState(walletId);
|
|
2328
|
+
const solanaAddress = { addressType: AddressType2.solana, address: publicKey };
|
|
2329
|
+
const hasSolana = state.addresses.some((addr) => addr.addressType === AddressType2.solana);
|
|
2330
|
+
const newAddresses = hasSolana ? state.addresses.map((addr) => addr.addressType === AddressType2.solana ? solanaAddress : addr) : [...state.addresses, solanaAddress];
|
|
2331
|
+
this.setWalletState(walletId, {
|
|
2332
|
+
connected: true,
|
|
2333
|
+
addresses: newAddresses
|
|
2334
|
+
});
|
|
750
2335
|
const authUserId = await this.getAuthUserId("Solana connect event");
|
|
751
2336
|
this.emit("connect", {
|
|
752
|
-
addresses:
|
|
2337
|
+
addresses: newAddresses,
|
|
753
2338
|
source: "injected-extension",
|
|
754
2339
|
authUserId
|
|
755
2340
|
});
|
|
756
2341
|
};
|
|
757
2342
|
const handleSolanaDisconnect = () => {
|
|
758
2343
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
|
|
759
|
-
|
|
760
|
-
|
|
2344
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2345
|
+
const state = this.getWalletState(walletId);
|
|
2346
|
+
const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
|
|
2347
|
+
this.setWalletState(walletId, {
|
|
2348
|
+
connected: filteredAddresses.length > 0,
|
|
2349
|
+
addresses: filteredAddresses
|
|
2350
|
+
});
|
|
761
2351
|
this.emit("disconnect", {
|
|
762
2352
|
source: "injected-extension"
|
|
763
2353
|
});
|
|
764
2354
|
};
|
|
765
2355
|
const handleSolanaAccountChanged = async (publicKey) => {
|
|
766
2356
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
2357
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2358
|
+
const state = this.getWalletState(walletId);
|
|
2359
|
+
const solanaIndex = state.addresses.findIndex((addr) => addr.addressType === AddressType2.solana);
|
|
2360
|
+
const newAddresses = solanaIndex >= 0 ? state.addresses.map(
|
|
2361
|
+
(addr, idx) => idx === solanaIndex ? { addressType: AddressType2.solana, address: publicKey } : addr
|
|
2362
|
+
) : [...state.addresses, { addressType: AddressType2.solana, address: publicKey }];
|
|
2363
|
+
this.setWalletState(walletId, {
|
|
2364
|
+
connected: true,
|
|
2365
|
+
addresses: newAddresses
|
|
2366
|
+
});
|
|
773
2367
|
const authUserId = await this.getAuthUserId("Solana account changed event");
|
|
774
2368
|
this.emit("connect", {
|
|
775
|
-
addresses:
|
|
2369
|
+
addresses: newAddresses,
|
|
776
2370
|
source: "injected-extension-account-change",
|
|
777
2371
|
authUserId
|
|
778
2372
|
});
|
|
779
2373
|
};
|
|
780
|
-
const cleanupConnect =
|
|
781
|
-
const cleanupDisconnect =
|
|
782
|
-
const cleanupAccountChanged =
|
|
2374
|
+
const cleanupConnect = phantom.solana.addEventListener("connect", handleSolanaConnect);
|
|
2375
|
+
const cleanupDisconnect = phantom.solana.addEventListener("disconnect", handleSolanaDisconnect);
|
|
2376
|
+
const cleanupAccountChanged = phantom.solana.addEventListener("accountChanged", handleSolanaAccountChanged);
|
|
783
2377
|
this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountChanged);
|
|
784
2378
|
}
|
|
785
|
-
setupEthereumEvents() {
|
|
2379
|
+
setupEthereumEvents(phantom) {
|
|
786
2380
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
|
|
787
2381
|
const handleEthereumConnect = async (accounts) => {
|
|
788
2382
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
}
|
|
798
|
-
this.connected = this.addresses.length > 0;
|
|
2383
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2384
|
+
const state = this.getWalletState(walletId);
|
|
2385
|
+
const ethAddresses = accounts.map((address) => ({ addressType: AddressType2.ethereum, address }));
|
|
2386
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
|
|
2387
|
+
const newAddresses = [...otherAddresses, ...ethAddresses];
|
|
2388
|
+
this.setWalletState(walletId, {
|
|
2389
|
+
connected: true,
|
|
2390
|
+
addresses: newAddresses
|
|
2391
|
+
});
|
|
799
2392
|
const authUserId = await this.getAuthUserId("Ethereum connect event");
|
|
800
2393
|
this.emit("connect", {
|
|
801
|
-
addresses:
|
|
2394
|
+
addresses: newAddresses,
|
|
802
2395
|
source: "injected-extension",
|
|
803
2396
|
authUserId
|
|
804
2397
|
});
|
|
805
2398
|
};
|
|
806
2399
|
const handleEthereumDisconnect = () => {
|
|
807
2400
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
|
|
808
|
-
|
|
809
|
-
|
|
2401
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2402
|
+
const state = this.getWalletState(walletId);
|
|
2403
|
+
const filteredAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
|
|
2404
|
+
this.setWalletState(walletId, {
|
|
2405
|
+
connected: filteredAddresses.length > 0,
|
|
2406
|
+
addresses: filteredAddresses
|
|
2407
|
+
});
|
|
810
2408
|
this.emit("disconnect", {
|
|
811
2409
|
source: "injected-extension"
|
|
812
2410
|
});
|
|
813
2411
|
};
|
|
814
2412
|
const handleEthereumAccountsChanged = async (accounts) => {
|
|
815
2413
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts });
|
|
816
|
-
|
|
2414
|
+
const walletId = this.selectedWalletId || "phantom";
|
|
2415
|
+
const state = this.getWalletState(walletId);
|
|
2416
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
|
|
817
2417
|
if (accounts && accounts.length > 0) {
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
);
|
|
2418
|
+
const ethAddresses = accounts.map((address) => ({ addressType: AddressType2.ethereum, address }));
|
|
2419
|
+
const newAddresses = [...otherAddresses, ...ethAddresses];
|
|
2420
|
+
this.setWalletState(walletId, {
|
|
2421
|
+
connected: true,
|
|
2422
|
+
addresses: newAddresses
|
|
2423
|
+
});
|
|
824
2424
|
const authUserId = await this.getAuthUserId("Ethereum accounts changed event");
|
|
825
2425
|
this.emit("connect", {
|
|
826
|
-
addresses:
|
|
2426
|
+
addresses: newAddresses,
|
|
827
2427
|
source: "injected-extension-account-change",
|
|
828
2428
|
authUserId
|
|
829
2429
|
});
|
|
830
2430
|
} else {
|
|
831
|
-
this.
|
|
2431
|
+
this.setWalletState(walletId, {
|
|
2432
|
+
connected: otherAddresses.length > 0,
|
|
2433
|
+
addresses: otherAddresses
|
|
2434
|
+
});
|
|
832
2435
|
this.emit("disconnect", {
|
|
833
2436
|
source: "injected-extension-account-change"
|
|
834
2437
|
});
|
|
835
2438
|
}
|
|
836
2439
|
};
|
|
837
|
-
const cleanupConnect =
|
|
838
|
-
const cleanupDisconnect =
|
|
839
|
-
const cleanupAccountsChanged =
|
|
840
|
-
"accountsChanged",
|
|
841
|
-
handleEthereumAccountsChanged
|
|
842
|
-
);
|
|
2440
|
+
const cleanupConnect = phantom.ethereum.addEventListener("connect", handleEthereumConnect);
|
|
2441
|
+
const cleanupDisconnect = phantom.ethereum.addEventListener("disconnect", handleEthereumDisconnect);
|
|
2442
|
+
const cleanupAccountsChanged = phantom.ethereum.addEventListener("accountsChanged", handleEthereumAccountsChanged);
|
|
843
2443
|
this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountsChanged);
|
|
844
2444
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
this.
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
2445
|
+
setupExternalWalletEvents(walletInfo) {
|
|
2446
|
+
if (isPhantomWallet(walletInfo)) {
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
if (!this.selectedWalletId || this.externalWalletEventListenersSetup.has(this.selectedWalletId)) {
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up external wallet event listeners", {
|
|
2453
|
+
walletId: this.selectedWalletId
|
|
2454
|
+
});
|
|
2455
|
+
if (walletInfo.providers?.ethereum) {
|
|
2456
|
+
const handleExternalEthereumAccountsChanged = async (accounts) => {
|
|
2457
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Ethereum accounts changed event received", {
|
|
2458
|
+
walletId: this.selectedWalletId,
|
|
2459
|
+
accounts
|
|
2460
|
+
});
|
|
2461
|
+
const walletId = this.selectedWalletId;
|
|
2462
|
+
const state = this.getWalletState(walletId);
|
|
2463
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.ethereum);
|
|
2464
|
+
if (accounts && accounts.length > 0) {
|
|
2465
|
+
const ethAddresses = accounts.map((address) => ({ addressType: AddressType2.ethereum, address }));
|
|
2466
|
+
const newAddresses = [...otherAddresses, ...ethAddresses];
|
|
2467
|
+
this.setWalletState(walletId, {
|
|
2468
|
+
connected: true,
|
|
2469
|
+
addresses: newAddresses
|
|
2470
|
+
});
|
|
2471
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Updated Ethereum addresses after account change", {
|
|
2472
|
+
walletId,
|
|
2473
|
+
oldCount: 0,
|
|
2474
|
+
// We filtered them out
|
|
2475
|
+
newCount: accounts.length,
|
|
2476
|
+
addresses: newAddresses.filter((addr) => addr.addressType === AddressType2.ethereum)
|
|
2477
|
+
});
|
|
2478
|
+
const authUserId = await this.getAuthUserId("External wallet Ethereum accounts changed event");
|
|
2479
|
+
this.emit("connect", {
|
|
2480
|
+
addresses: newAddresses,
|
|
2481
|
+
source: "external-wallet-account-change",
|
|
2482
|
+
authUserId
|
|
2483
|
+
});
|
|
2484
|
+
} else {
|
|
2485
|
+
this.setWalletState(walletId, {
|
|
2486
|
+
connected: otherAddresses.length > 0,
|
|
2487
|
+
addresses: otherAddresses
|
|
2488
|
+
});
|
|
2489
|
+
this.emit("disconnect", {
|
|
2490
|
+
source: "external-wallet-account-change"
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
};
|
|
2494
|
+
if (typeof walletInfo.providers.ethereum.on === "function") {
|
|
2495
|
+
walletInfo.providers.ethereum.on("accountsChanged", handleExternalEthereumAccountsChanged);
|
|
2496
|
+
this.browserInjectedCleanupFunctions.push(() => {
|
|
2497
|
+
if (typeof walletInfo.providers?.ethereum?.off === "function") {
|
|
2498
|
+
walletInfo.providers.ethereum.off("accountsChanged", handleExternalEthereumAccountsChanged);
|
|
2499
|
+
}
|
|
2500
|
+
});
|
|
865
2501
|
}
|
|
866
|
-
}
|
|
2502
|
+
}
|
|
2503
|
+
if (walletInfo.providers?.solana) {
|
|
2504
|
+
const handleExternalSolanaAccountChanged = async (publicKey) => {
|
|
2505
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "External wallet Solana account changed event received", {
|
|
2506
|
+
walletId: this.selectedWalletId,
|
|
2507
|
+
publicKey
|
|
2508
|
+
});
|
|
2509
|
+
const walletId = this.selectedWalletId;
|
|
2510
|
+
const state = this.getWalletState(walletId);
|
|
2511
|
+
const otherAddresses = state.addresses.filter((addr) => addr.addressType !== AddressType2.solana);
|
|
2512
|
+
if (publicKey) {
|
|
2513
|
+
const newAddresses = [...otherAddresses, { addressType: AddressType2.solana, address: publicKey }];
|
|
2514
|
+
this.setWalletState(walletId, {
|
|
2515
|
+
connected: true,
|
|
2516
|
+
addresses: newAddresses
|
|
2517
|
+
});
|
|
2518
|
+
const authUserId = await this.getAuthUserId("External wallet Solana account changed event");
|
|
2519
|
+
this.emit("connect", {
|
|
2520
|
+
addresses: newAddresses,
|
|
2521
|
+
source: "external-wallet-account-change",
|
|
2522
|
+
authUserId
|
|
2523
|
+
});
|
|
2524
|
+
} else {
|
|
2525
|
+
this.setWalletState(walletId, {
|
|
2526
|
+
connected: otherAddresses.length > 0,
|
|
2527
|
+
addresses: otherAddresses
|
|
2528
|
+
});
|
|
2529
|
+
this.emit("disconnect", {
|
|
2530
|
+
source: "external-wallet-account-change"
|
|
2531
|
+
});
|
|
2532
|
+
}
|
|
2533
|
+
};
|
|
2534
|
+
if (typeof walletInfo.providers.solana.on === "function") {
|
|
2535
|
+
walletInfo.providers.solana.on("accountChanged", handleExternalSolanaAccountChanged);
|
|
2536
|
+
this.browserInjectedCleanupFunctions.push(() => {
|
|
2537
|
+
if (typeof walletInfo.providers?.solana?.off === "function") {
|
|
2538
|
+
walletInfo.providers.solana.off("accountChanged", handleExternalSolanaAccountChanged);
|
|
2539
|
+
}
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
if (this.selectedWalletId) {
|
|
2544
|
+
this.externalWalletEventListenersSetup.add(this.selectedWalletId);
|
|
2545
|
+
}
|
|
867
2546
|
}
|
|
868
2547
|
};
|
|
869
2548
|
|
|
@@ -1178,7 +2857,7 @@ var BrowserAuthProvider = class {
|
|
|
1178
2857
|
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
1179
2858
|
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
1180
2859
|
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
1181
|
-
sdk_version: "1.0.0-beta.
|
|
2860
|
+
sdk_version: "1.0.0-beta.24",
|
|
1182
2861
|
sdk_type: "browser",
|
|
1183
2862
|
platform: detectBrowser().name
|
|
1184
2863
|
});
|
|
@@ -1299,10 +2978,10 @@ var BrowserAuthProvider = class {
|
|
|
1299
2978
|
};
|
|
1300
2979
|
|
|
1301
2980
|
// src/providers/embedded/adapters/phantom-app.ts
|
|
1302
|
-
import { isPhantomExtensionInstalled as
|
|
2981
|
+
import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
|
|
1303
2982
|
|
|
1304
2983
|
// src/isPhantomLoginAvailable.ts
|
|
1305
|
-
import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
|
|
2984
|
+
import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
|
|
1306
2985
|
async function isPhantomLoginAvailable(timeoutMs = 3e3) {
|
|
1307
2986
|
const extensionInstalled = await waitForExtension(timeoutMs);
|
|
1308
2987
|
if (!extensionInstalled) {
|
|
@@ -1328,7 +3007,7 @@ async function waitForExtension(timeoutMs) {
|
|
|
1328
3007
|
const checkInterval = 100;
|
|
1329
3008
|
const checkForExtension = () => {
|
|
1330
3009
|
try {
|
|
1331
|
-
if (
|
|
3010
|
+
if (isPhantomExtensionInstalled2()) {
|
|
1332
3011
|
resolve(true);
|
|
1333
3012
|
return;
|
|
1334
3013
|
}
|
|
@@ -1351,7 +3030,7 @@ var BrowserPhantomAppProvider = class {
|
|
|
1351
3030
|
* Check if the Phantom extension is installed in the browser
|
|
1352
3031
|
*/
|
|
1353
3032
|
isAvailable() {
|
|
1354
|
-
return
|
|
3033
|
+
return isPhantomExtensionInstalled3();
|
|
1355
3034
|
}
|
|
1356
3035
|
/**
|
|
1357
3036
|
* Authenticate using the Phantom browser extension
|
|
@@ -1442,15 +3121,19 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1442
3121
|
// Full user agent for more detailed info
|
|
1443
3122
|
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1444
3123
|
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1445
|
-
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.
|
|
3124
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.24"
|
|
1446
3125
|
// Replaced at build time
|
|
1447
3126
|
}
|
|
1448
3127
|
};
|
|
1449
3128
|
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
|
|
1450
3129
|
const logger = new BrowserLogger();
|
|
1451
3130
|
super(config, platform, logger);
|
|
3131
|
+
this.addressTypes = config.addressTypes;
|
|
1452
3132
|
debug.info(DebugCategory.EMBEDDED_PROVIDER, "Browser EmbeddedProvider initialized");
|
|
1453
3133
|
}
|
|
3134
|
+
getEnabledAddressTypes() {
|
|
3135
|
+
return this.addressTypes;
|
|
3136
|
+
}
|
|
1454
3137
|
};
|
|
1455
3138
|
|
|
1456
3139
|
// src/ProviderManager.ts
|
|
@@ -1858,37 +3541,14 @@ var ProviderManager = class {
|
|
|
1858
3541
|
}
|
|
1859
3542
|
};
|
|
1860
3543
|
|
|
1861
|
-
// src/waitForPhantomExtension.ts
|
|
1862
|
-
import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
|
|
1863
|
-
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1864
|
-
return new Promise((resolve) => {
|
|
1865
|
-
const startTime = Date.now();
|
|
1866
|
-
const checkInterval = 100;
|
|
1867
|
-
const checkForExtension = () => {
|
|
1868
|
-
try {
|
|
1869
|
-
if (isPhantomExtensionInstalled3()) {
|
|
1870
|
-
resolve(true);
|
|
1871
|
-
return;
|
|
1872
|
-
}
|
|
1873
|
-
} catch (error) {
|
|
1874
|
-
}
|
|
1875
|
-
const elapsed = Date.now() - startTime;
|
|
1876
|
-
if (elapsed >= timeoutMs) {
|
|
1877
|
-
resolve(false);
|
|
1878
|
-
return;
|
|
1879
|
-
}
|
|
1880
|
-
setTimeout(checkForExtension, checkInterval);
|
|
1881
|
-
};
|
|
1882
|
-
checkForExtension();
|
|
1883
|
-
});
|
|
1884
|
-
}
|
|
1885
|
-
|
|
1886
3544
|
// src/BrowserSDK.ts
|
|
1887
3545
|
import { EMBEDDED_PROVIDER_AUTH_TYPES as EMBEDDED_PROVIDER_AUTH_TYPES2 } from "@phantom/embedded-provider-core";
|
|
1888
3546
|
import { DEFAULT_EMBEDDED_WALLET_TYPE as DEFAULT_EMBEDDED_WALLET_TYPE2 } from "@phantom/constants";
|
|
1889
3547
|
var BROWSER_SDK_PROVIDER_TYPES = [...EMBEDDED_PROVIDER_AUTH_TYPES2, "injected"];
|
|
1890
3548
|
var BrowserSDK = class {
|
|
1891
3549
|
constructor(config) {
|
|
3550
|
+
this.walletRegistry = getWalletRegistry();
|
|
3551
|
+
this.isLoading = true;
|
|
1892
3552
|
debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
|
|
1893
3553
|
providers: config.providers,
|
|
1894
3554
|
embeddedWalletType: config.embeddedWalletType,
|
|
@@ -1924,7 +3584,14 @@ var BrowserSDK = class {
|
|
|
1924
3584
|
`Invalid embeddedWalletType: ${config.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
|
|
1925
3585
|
);
|
|
1926
3586
|
}
|
|
3587
|
+
this.config = config;
|
|
1927
3588
|
this.providerManager = new ProviderManager(config);
|
|
3589
|
+
void this.discoverWallets();
|
|
3590
|
+
}
|
|
3591
|
+
discoverWallets() {
|
|
3592
|
+
return this.walletRegistry.discover(this.config.addressTypes).finally(() => {
|
|
3593
|
+
this.isLoading = false;
|
|
3594
|
+
});
|
|
1928
3595
|
}
|
|
1929
3596
|
// ===== CHAIN API =====
|
|
1930
3597
|
/**
|
|
@@ -1997,13 +3664,20 @@ var BrowserSDK = class {
|
|
|
1997
3664
|
getCurrentProviderInfo() {
|
|
1998
3665
|
return this.providerManager.getCurrentProviderInfo();
|
|
1999
3666
|
}
|
|
2000
|
-
// ===== UTILITY METHODS =====
|
|
2001
3667
|
/**
|
|
2002
|
-
*
|
|
3668
|
+
* Get enabled address types for the current provider
|
|
3669
|
+
* - For embedded provider: returns config.addressTypes
|
|
3670
|
+
* - For Phantom injected: returns config.addressTypes
|
|
3671
|
+
* - For discovered wallets: returns the wallet's addressTypes from registry
|
|
2003
3672
|
*/
|
|
2004
|
-
|
|
2005
|
-
|
|
3673
|
+
getEnabledAddressTypes() {
|
|
3674
|
+
const currentProvider = this.providerManager.getCurrentProvider();
|
|
3675
|
+
if (!currentProvider) {
|
|
3676
|
+
return [];
|
|
3677
|
+
}
|
|
3678
|
+
return currentProvider.getEnabledAddressTypes();
|
|
2006
3679
|
}
|
|
3680
|
+
// ===== UTILITY METHODS =====
|
|
2007
3681
|
/**
|
|
2008
3682
|
* Add event listener for provider events (connect, connect_start, connect_error, disconnect, error)
|
|
2009
3683
|
* Works with both embedded and injected providers
|
|
@@ -2036,40 +3710,21 @@ var BrowserSDK = class {
|
|
|
2036
3710
|
debug.log(DebugCategory.BROWSER_SDK, "Auto-connect failed for all providers");
|
|
2037
3711
|
}
|
|
2038
3712
|
}
|
|
2039
|
-
/**
|
|
2040
|
-
* Debug configuration methods
|
|
2041
|
-
* These allow dynamic debug configuration without SDK reinstantiation
|
|
2042
|
-
*/
|
|
2043
|
-
/**
|
|
2044
|
-
* Enable debug logging
|
|
2045
|
-
*/
|
|
2046
3713
|
enableDebug() {
|
|
2047
3714
|
debug.enable();
|
|
2048
3715
|
debug.info(DebugCategory.BROWSER_SDK, "Debug logging enabled");
|
|
2049
3716
|
}
|
|
2050
|
-
/**
|
|
2051
|
-
* Disable debug logging
|
|
2052
|
-
*/
|
|
2053
3717
|
disableDebug() {
|
|
2054
3718
|
debug.disable();
|
|
2055
3719
|
}
|
|
2056
|
-
/**
|
|
2057
|
-
* Set debug level
|
|
2058
|
-
*/
|
|
2059
3720
|
setDebugLevel(level) {
|
|
2060
3721
|
debug.setLevel(level);
|
|
2061
3722
|
debug.info(DebugCategory.BROWSER_SDK, "Debug level updated", { level });
|
|
2062
3723
|
}
|
|
2063
|
-
/**
|
|
2064
|
-
* Set debug callback function
|
|
2065
|
-
*/
|
|
2066
3724
|
setDebugCallback(callback) {
|
|
2067
3725
|
debug.setCallback(callback);
|
|
2068
3726
|
debug.info(DebugCategory.BROWSER_SDK, "Debug callback updated");
|
|
2069
3727
|
}
|
|
2070
|
-
/**
|
|
2071
|
-
* Configure debug settings all at once
|
|
2072
|
-
*/
|
|
2073
3728
|
configureDebug(config) {
|
|
2074
3729
|
if (config.enabled !== void 0) {
|
|
2075
3730
|
if (config.enabled) {
|
|
@@ -2175,6 +3830,22 @@ var BrowserSDK = class {
|
|
|
2175
3830
|
throw error;
|
|
2176
3831
|
}
|
|
2177
3832
|
}
|
|
3833
|
+
getDiscoveredWallets() {
|
|
3834
|
+
debug.log(DebugCategory.BROWSER_SDK, "Getting discovered wallets");
|
|
3835
|
+
try {
|
|
3836
|
+
const allWallets = this.walletRegistry.getByAddressTypes(this.config.addressTypes);
|
|
3837
|
+
debug.log(DebugCategory.BROWSER_SDK, "Retrieved discovered wallets", {
|
|
3838
|
+
count: allWallets.length,
|
|
3839
|
+
walletIds: allWallets.map((w) => w.id)
|
|
3840
|
+
});
|
|
3841
|
+
return allWallets;
|
|
3842
|
+
} catch (error) {
|
|
3843
|
+
debug.error(DebugCategory.BROWSER_SDK, "Failed to get discovered wallets", {
|
|
3844
|
+
error: error.message
|
|
3845
|
+
});
|
|
3846
|
+
return [];
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
2178
3849
|
};
|
|
2179
3850
|
|
|
2180
3851
|
// src/utils/deeplink.ts
|
|
@@ -2187,11 +3858,36 @@ function getDeeplinkToPhantom(ref) {
|
|
|
2187
3858
|
return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
|
|
2188
3859
|
}
|
|
2189
3860
|
|
|
3861
|
+
// src/waitForPhantomExtension.ts
|
|
3862
|
+
import { isPhantomExtensionInstalled as isPhantomExtensionInstalled4 } from "@phantom/browser-injected-sdk";
|
|
3863
|
+
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
3864
|
+
return new Promise((resolve) => {
|
|
3865
|
+
const startTime = Date.now();
|
|
3866
|
+
const checkInterval = 100;
|
|
3867
|
+
const checkForExtension = () => {
|
|
3868
|
+
try {
|
|
3869
|
+
if (isPhantomExtensionInstalled4()) {
|
|
3870
|
+
resolve(true);
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
} catch (error) {
|
|
3874
|
+
}
|
|
3875
|
+
const elapsed = Date.now() - startTime;
|
|
3876
|
+
if (elapsed >= timeoutMs) {
|
|
3877
|
+
resolve(false);
|
|
3878
|
+
return;
|
|
3879
|
+
}
|
|
3880
|
+
setTimeout(checkForExtension, checkInterval);
|
|
3881
|
+
};
|
|
3882
|
+
checkForExtension();
|
|
3883
|
+
});
|
|
3884
|
+
}
|
|
3885
|
+
|
|
2190
3886
|
// src/index.ts
|
|
2191
3887
|
import { NetworkId } from "@phantom/constants";
|
|
2192
|
-
import { AddressType as
|
|
3888
|
+
import { AddressType as AddressType3 } from "@phantom/client";
|
|
2193
3889
|
export {
|
|
2194
|
-
|
|
3890
|
+
AddressType3 as AddressType,
|
|
2195
3891
|
BrowserSDK,
|
|
2196
3892
|
DebugCategory,
|
|
2197
3893
|
DebugLevel,
|