@phantom/browser-sdk 0.0.10 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +648 -100
- package/dist/index.d.ts +118 -3
- package/dist/index.js +769 -10
- package/dist/index.mjs +767 -8
- package/package.json +26 -29
- package/dist/auto-confirm/index.d.ts +0 -10
- package/dist/auto-confirm/index.js +0 -107
- package/dist/auto-confirm/index.mjs +0 -82
- package/dist/chunk-GV6AIHPN.mjs +0 -18
- package/dist/extension/index.d.ts +0 -10
- package/dist/extension/index.js +0 -50
- package/dist/extension/index.mjs +0 -25
- package/dist/index-52a9bded.d.ts +0 -182
- package/dist/solana/index.d.ts +0 -10
- package/dist/solana/index.js +0 -550
- package/dist/solana/index.mjs +0 -515
package/dist/index.js
CHANGED
|
@@ -20,17 +20,776 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
-
|
|
23
|
+
AddressType: () => import_client3.AddressType,
|
|
24
|
+
BrowserSDK: () => BrowserSDK,
|
|
25
|
+
NetworkId: () => import_client3.NetworkId
|
|
24
26
|
});
|
|
25
27
|
module.exports = __toCommonJS(src_exports);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
|
|
29
|
+
// src/providers/injected/index.ts
|
|
30
|
+
var import_client = require("@phantom/client");
|
|
31
|
+
var import_browser_injected_sdk = require("@phantom/browser-injected-sdk");
|
|
32
|
+
var import_solana = require("@phantom/browser-injected-sdk/solana");
|
|
33
|
+
var import_ethereum = require("@phantom/browser-injected-sdk/ethereum");
|
|
34
|
+
var InjectedProvider = class {
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.connected = false;
|
|
37
|
+
this.addresses = [];
|
|
38
|
+
this.addressTypes = config.addressTypes || [import_client.AddressType.solana, import_client.AddressType.ethereum];
|
|
39
|
+
const plugins = [(0, import_browser_injected_sdk.createExtensionPlugin)()];
|
|
40
|
+
if (this.addressTypes.includes(import_client.AddressType.solana)) {
|
|
41
|
+
plugins.push((0, import_solana.createSolanaPlugin)());
|
|
42
|
+
}
|
|
43
|
+
if (this.addressTypes.includes(import_client.AddressType.ethereum)) {
|
|
44
|
+
plugins.push((0, import_ethereum.createEthereumPlugin)());
|
|
45
|
+
}
|
|
46
|
+
this.phantom = (0, import_browser_injected_sdk.createPhantom)({ plugins });
|
|
47
|
+
}
|
|
48
|
+
async connect() {
|
|
49
|
+
if (!this.phantom.extension.isInstalled()) {
|
|
50
|
+
throw new Error("Phantom wallet not found");
|
|
51
|
+
}
|
|
52
|
+
const connectedAddresses = [];
|
|
53
|
+
if (this.addressTypes.includes(import_client.AddressType.solana)) {
|
|
54
|
+
try {
|
|
55
|
+
const publicKey = await this.phantom.solana.connect();
|
|
56
|
+
if (publicKey) {
|
|
57
|
+
connectedAddresses.push({
|
|
58
|
+
addressType: import_client.AddressType.solana,
|
|
59
|
+
address: publicKey
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error("Failed to connect Solana:", err);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (this.addressTypes.includes(import_client.AddressType.ethereum)) {
|
|
67
|
+
try {
|
|
68
|
+
const accounts = await this.phantom.ethereum.connect();
|
|
69
|
+
if (accounts && accounts.length > 0) {
|
|
70
|
+
connectedAddresses.push(
|
|
71
|
+
...accounts.map((address) => ({
|
|
72
|
+
addressType: import_client.AddressType.ethereum,
|
|
73
|
+
address
|
|
74
|
+
}))
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error("Failed to connect Ethereum:", err);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (connectedAddresses.length === 0) {
|
|
82
|
+
throw new Error("Failed to connect to any supported wallet provider");
|
|
83
|
+
}
|
|
84
|
+
this.addresses = connectedAddresses;
|
|
85
|
+
this.connected = true;
|
|
86
|
+
return {
|
|
87
|
+
addresses: this.addresses
|
|
88
|
+
// walletId is not applicable for injected providers
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
async disconnect() {
|
|
92
|
+
if (this.addressTypes.includes(import_client.AddressType.solana)) {
|
|
93
|
+
try {
|
|
94
|
+
await this.phantom.solana.disconnect();
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error("Failed to disconnect Solana:", err);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (this.addressTypes.includes(import_client.AddressType.ethereum)) {
|
|
100
|
+
try {
|
|
101
|
+
await this.phantom.ethereum.disconnect();
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error("Failed to disconnect Ethereum:", err);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.connected = false;
|
|
107
|
+
this.addresses = [];
|
|
108
|
+
}
|
|
109
|
+
async signMessage(params) {
|
|
110
|
+
if (!this.connected) {
|
|
111
|
+
throw new Error("Wallet not connected");
|
|
112
|
+
}
|
|
113
|
+
const networkPrefix = params.networkId.split(":")[0].toLowerCase();
|
|
114
|
+
if (networkPrefix === "solana") {
|
|
115
|
+
const { signature } = await this.phantom.solana.signMessage(new TextEncoder().encode(params.message));
|
|
116
|
+
return Array.from(signature).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
117
|
+
} else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
|
|
118
|
+
const address = this.addresses.find((addr) => addr.addressType === import_client.AddressType.ethereum)?.address;
|
|
119
|
+
if (!address) {
|
|
120
|
+
throw new Error("No address available");
|
|
121
|
+
}
|
|
122
|
+
const signature = await this.phantom.ethereum.signPersonalMessage(params.message, address);
|
|
123
|
+
return signature;
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
|
|
126
|
+
}
|
|
127
|
+
async signAndSendTransaction(params) {
|
|
128
|
+
if (!this.connected) {
|
|
129
|
+
throw new Error("Wallet not connected");
|
|
130
|
+
}
|
|
131
|
+
const networkPrefix = params.networkId.split(":")[0].toLowerCase();
|
|
132
|
+
if (networkPrefix === "solana") {
|
|
133
|
+
const transaction = params.transaction;
|
|
134
|
+
const result = await this.phantom.solana.signAndSendTransaction(transaction);
|
|
135
|
+
return {
|
|
136
|
+
rawTransaction: result.signature
|
|
137
|
+
};
|
|
138
|
+
} else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
|
|
139
|
+
const toHex = (value) => {
|
|
140
|
+
if (!value)
|
|
141
|
+
return void 0;
|
|
142
|
+
if (typeof value === "string" && value.startsWith("0x"))
|
|
143
|
+
return value;
|
|
144
|
+
if (typeof value === "string")
|
|
145
|
+
return value;
|
|
146
|
+
return "0x" + value.toString(16);
|
|
147
|
+
};
|
|
148
|
+
const txRequest = {
|
|
149
|
+
to: params.transaction.to,
|
|
150
|
+
value: params.transaction.value ? toHex(params.transaction.value) : "0x0",
|
|
151
|
+
gas: toHex(params.transaction.gas),
|
|
152
|
+
gasPrice: toHex(params.transaction.gasPrice),
|
|
153
|
+
maxFeePerGas: toHex(params.transaction.maxFeePerGas),
|
|
154
|
+
maxPriorityFeePerGas: toHex(params.transaction.maxPriorityFeePerGas),
|
|
155
|
+
data: params.transaction.data || "0x"
|
|
156
|
+
};
|
|
157
|
+
const txHash = await this.phantom.ethereum.sendTransaction(txRequest);
|
|
158
|
+
return {
|
|
159
|
+
rawTransaction: txHash
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
|
|
163
|
+
}
|
|
164
|
+
getAddresses() {
|
|
165
|
+
return this.addresses;
|
|
166
|
+
}
|
|
167
|
+
isConnected() {
|
|
168
|
+
return this.connected;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/providers/embedded/index.ts
|
|
173
|
+
var import_client2 = require("@phantom/client");
|
|
174
|
+
var import_api_key_stamper = require("@phantom/api-key-stamper");
|
|
175
|
+
|
|
176
|
+
// src/providers/embedded/storage.ts
|
|
177
|
+
var IndexedDBStorage = class {
|
|
178
|
+
constructor() {
|
|
179
|
+
this.dbName = "phantom-browser-sdk";
|
|
180
|
+
this.storeName = "sessions";
|
|
181
|
+
this.version = 1;
|
|
182
|
+
}
|
|
183
|
+
async getDB() {
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
const request = indexedDB.open(this.dbName, this.version);
|
|
186
|
+
request.onerror = () => reject(request.error);
|
|
187
|
+
request.onsuccess = () => resolve(request.result);
|
|
188
|
+
request.onupgradeneeded = (event) => {
|
|
189
|
+
const db = event.target.result;
|
|
190
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
191
|
+
db.createObjectStore(this.storeName);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
async getSession() {
|
|
197
|
+
const db = await this.getDB();
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
const transaction = db.transaction([this.storeName], "readonly");
|
|
200
|
+
const store = transaction.objectStore(this.storeName);
|
|
201
|
+
const request = store.get("currentSession");
|
|
202
|
+
request.onsuccess = () => resolve(request.result || null);
|
|
203
|
+
request.onerror = () => reject(request.error);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async saveSession(session) {
|
|
207
|
+
const db = await this.getDB();
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
210
|
+
const store = transaction.objectStore(this.storeName);
|
|
211
|
+
const request = store.put(session, "currentSession");
|
|
212
|
+
request.onsuccess = () => resolve();
|
|
213
|
+
request.onerror = () => reject(request.error);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
async clearSession() {
|
|
217
|
+
const db = await this.getDB();
|
|
218
|
+
return new Promise((resolve, reject) => {
|
|
219
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
220
|
+
const store = transaction.objectStore(this.storeName);
|
|
221
|
+
const request = store.delete("currentSession");
|
|
222
|
+
request.onsuccess = () => resolve();
|
|
223
|
+
request.onerror = () => reject(request.error);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// src/providers/embedded/auth.ts
|
|
229
|
+
var IframeAuth = class {
|
|
230
|
+
async authenticate(_options) {
|
|
231
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
232
|
+
return {
|
|
233
|
+
walletId: `wallet-${Date.now()}`
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// src/parsers/index.ts
|
|
239
|
+
var import_base64url = require("@phantom/base64url");
|
|
240
|
+
|
|
241
|
+
// src/polyfills.ts
|
|
242
|
+
var import_buffer = require("buffer");
|
|
243
|
+
var import_jose = require("jose");
|
|
244
|
+
|
|
245
|
+
// src/parsers/index.ts
|
|
246
|
+
function parseMessage(message) {
|
|
247
|
+
return {
|
|
248
|
+
base64url: (0, import_base64url.stringToBase64url)(message)
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
async function parseTransaction(transaction, networkId) {
|
|
252
|
+
const networkPrefix = networkId.split(":")[0].toLowerCase();
|
|
253
|
+
switch (networkPrefix) {
|
|
254
|
+
case "solana":
|
|
255
|
+
return parseSolanaTransaction(transaction);
|
|
256
|
+
case "ethereum":
|
|
257
|
+
case "polygon":
|
|
258
|
+
return parseEVMTransaction(transaction);
|
|
259
|
+
case "sui":
|
|
260
|
+
return await parseSuiTransaction(transaction);
|
|
261
|
+
case "bitcoin":
|
|
262
|
+
return parseBitcoinTransaction(transaction);
|
|
263
|
+
default:
|
|
264
|
+
throw new Error(`Unsupported network: ${networkPrefix}`);
|
|
30
265
|
}
|
|
31
|
-
return phantom;
|
|
32
266
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
267
|
+
function parseSolanaTransaction(transaction) {
|
|
268
|
+
if (transaction?.messageBytes != null) {
|
|
269
|
+
return {
|
|
270
|
+
base64url: (0, import_base64url.base64urlEncode)(transaction.messageBytes),
|
|
271
|
+
originalFormat: "@solana/kit"
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (typeof transaction?.serialize === "function") {
|
|
275
|
+
const serialized = transaction.serialize();
|
|
276
|
+
return {
|
|
277
|
+
base64url: (0, import_base64url.base64urlEncode)(serialized),
|
|
278
|
+
originalFormat: "@solana/web3.js"
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (transaction instanceof Uint8Array) {
|
|
282
|
+
return {
|
|
283
|
+
base64url: (0, import_base64url.base64urlEncode)(transaction),
|
|
284
|
+
originalFormat: "bytes"
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
throw new Error("Unsupported Solana transaction format");
|
|
288
|
+
}
|
|
289
|
+
function parseEVMTransaction(transaction) {
|
|
290
|
+
if (transaction && typeof transaction === "object" && (transaction.to || transaction.data)) {
|
|
291
|
+
const bytes = new TextEncoder().encode(
|
|
292
|
+
JSON.stringify(transaction, (_key, value) => typeof value === "bigint" ? value.toString() : value)
|
|
293
|
+
);
|
|
294
|
+
return {
|
|
295
|
+
base64url: (0, import_base64url.base64urlEncode)(bytes),
|
|
296
|
+
originalFormat: "viem"
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
if (transaction?.serialize && typeof transaction.serialize === "function") {
|
|
300
|
+
const serialized = transaction.serialize();
|
|
301
|
+
const bytes = new Uint8Array(import_buffer.Buffer.from(serialized.slice(2), "hex"));
|
|
302
|
+
return {
|
|
303
|
+
base64url: (0, import_base64url.base64urlEncode)(bytes),
|
|
304
|
+
originalFormat: "ethers"
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (transaction instanceof Uint8Array) {
|
|
308
|
+
return {
|
|
309
|
+
base64url: (0, import_base64url.base64urlEncode)(transaction),
|
|
310
|
+
originalFormat: "bytes"
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
if (typeof transaction === "string" && transaction.startsWith("0x")) {
|
|
314
|
+
const bytes = new Uint8Array(import_buffer.Buffer.from(transaction.slice(2), "hex"));
|
|
315
|
+
return {
|
|
316
|
+
base64url: (0, import_base64url.base64urlEncode)(bytes),
|
|
317
|
+
originalFormat: "hex"
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
throw new Error("Unsupported EVM transaction format");
|
|
321
|
+
}
|
|
322
|
+
async function parseSuiTransaction(transaction) {
|
|
323
|
+
if (transaction?.serialize && typeof transaction.serialize === "function") {
|
|
324
|
+
const serialized = transaction.serialize();
|
|
325
|
+
return {
|
|
326
|
+
base64url: (0, import_base64url.base64urlEncode)(serialized),
|
|
327
|
+
originalFormat: "sui-sdk"
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (transaction instanceof Uint8Array) {
|
|
331
|
+
return {
|
|
332
|
+
base64url: (0, import_base64url.base64urlEncode)(transaction),
|
|
333
|
+
originalFormat: "bytes"
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
if (transaction?.build && typeof transaction.build === "function") {
|
|
337
|
+
const built = await transaction.build();
|
|
338
|
+
if (built?.serialize && typeof built.serialize === "function") {
|
|
339
|
+
const serialized = built.serialize();
|
|
340
|
+
return {
|
|
341
|
+
base64url: (0, import_base64url.base64urlEncode)(serialized),
|
|
342
|
+
originalFormat: "transaction-block"
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
throw new Error("Unsupported Sui transaction format");
|
|
347
|
+
}
|
|
348
|
+
function parseBitcoinTransaction(transaction) {
|
|
349
|
+
if (transaction?.toBuffer && typeof transaction.toBuffer === "function") {
|
|
350
|
+
const buffer = transaction.toBuffer();
|
|
351
|
+
return {
|
|
352
|
+
base64url: (0, import_base64url.base64urlEncode)(new Uint8Array(buffer)),
|
|
353
|
+
originalFormat: "bitcoinjs-lib"
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
if (transaction instanceof Uint8Array) {
|
|
357
|
+
return {
|
|
358
|
+
base64url: (0, import_base64url.base64urlEncode)(transaction),
|
|
359
|
+
originalFormat: "bytes"
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (typeof transaction === "string") {
|
|
363
|
+
const bytes = new Uint8Array(import_buffer.Buffer.from(transaction, "hex"));
|
|
364
|
+
return {
|
|
365
|
+
base64url: (0, import_base64url.base64urlEncode)(bytes),
|
|
366
|
+
originalFormat: "hex"
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
throw new Error("Unsupported Bitcoin transaction format");
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// src/providers/embedded/index.ts
|
|
373
|
+
var EmbeddedProvider = class {
|
|
374
|
+
constructor(config) {
|
|
375
|
+
this.client = null;
|
|
376
|
+
this.walletId = null;
|
|
377
|
+
this.addresses = [];
|
|
378
|
+
this.config = config;
|
|
379
|
+
this.storage = new IndexedDBStorage();
|
|
380
|
+
config.solanaProvider;
|
|
381
|
+
}
|
|
382
|
+
async connect() {
|
|
383
|
+
let session = await this.storage.getSession();
|
|
384
|
+
if (!session) {
|
|
385
|
+
const keypair = (0, import_client2.generateKeyPair)();
|
|
386
|
+
const stamper2 = new import_api_key_stamper.ApiKeyStamper({
|
|
387
|
+
apiSecretKey: keypair.secretKey
|
|
388
|
+
});
|
|
389
|
+
const tempClient = new import_client2.PhantomClient(
|
|
390
|
+
{
|
|
391
|
+
apiBaseUrl: this.config.apiBaseUrl
|
|
392
|
+
},
|
|
393
|
+
stamper2
|
|
394
|
+
);
|
|
395
|
+
const uid = Date.now();
|
|
396
|
+
const organizationName = `${this.config.organizationId}-${uid}`;
|
|
397
|
+
const { organizationId } = await tempClient.createOrganization(organizationName, keypair);
|
|
398
|
+
let walletId;
|
|
399
|
+
if (this.config.embeddedWalletType === "user-wallet") {
|
|
400
|
+
const auth = new IframeAuth();
|
|
401
|
+
const authResult = await auth.authenticate({
|
|
402
|
+
iframeUrl: this.config.authUrl || "https://auth-flow.phantom.app",
|
|
403
|
+
organizationId,
|
|
404
|
+
parentOrganizationId: this.config.organizationId,
|
|
405
|
+
embeddedWalletType: this.config.embeddedWalletType
|
|
406
|
+
});
|
|
407
|
+
walletId = authResult.walletId;
|
|
408
|
+
} else {
|
|
409
|
+
const wallet = await tempClient.createWallet(`Wallet ${Date.now()}`);
|
|
410
|
+
walletId = wallet.walletId;
|
|
411
|
+
}
|
|
412
|
+
session = {
|
|
413
|
+
walletId,
|
|
414
|
+
organizationId: this.config.organizationId,
|
|
415
|
+
keypair
|
|
416
|
+
};
|
|
417
|
+
await this.storage.saveSession(session);
|
|
418
|
+
}
|
|
419
|
+
const stamper = new import_api_key_stamper.ApiKeyStamper({
|
|
420
|
+
apiSecretKey: session.keypair.secretKey
|
|
421
|
+
});
|
|
422
|
+
this.client = new import_client2.PhantomClient(
|
|
423
|
+
{
|
|
424
|
+
apiBaseUrl: this.config.apiBaseUrl,
|
|
425
|
+
organizationId: session.organizationId
|
|
426
|
+
},
|
|
427
|
+
stamper
|
|
428
|
+
);
|
|
429
|
+
this.walletId = session.walletId;
|
|
430
|
+
const addresses = await this.client.getWalletAddresses(session.walletId);
|
|
431
|
+
this.addresses = addresses.filter((addr) => this.config.addressTypes.some((type) => type === addr.addressType)).map((addr) => ({
|
|
432
|
+
addressType: addr.addressType,
|
|
433
|
+
address: addr.address
|
|
434
|
+
}));
|
|
435
|
+
return {
|
|
436
|
+
walletId: this.walletId,
|
|
437
|
+
addresses: this.addresses
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
async disconnect() {
|
|
441
|
+
await this.storage.clearSession();
|
|
442
|
+
this.client = null;
|
|
443
|
+
this.walletId = null;
|
|
444
|
+
this.addresses = [];
|
|
445
|
+
}
|
|
446
|
+
async signMessage(params) {
|
|
447
|
+
if (!this.client || !this.walletId) {
|
|
448
|
+
throw new Error("Not connected");
|
|
449
|
+
}
|
|
450
|
+
const parsedMessage = parseMessage(params.message);
|
|
451
|
+
return await this.client.signMessage(this.walletId, parsedMessage.base64url, params.networkId);
|
|
452
|
+
}
|
|
453
|
+
async signAndSendTransaction(params) {
|
|
454
|
+
if (!this.client || !this.walletId) {
|
|
455
|
+
throw new Error("Not connected");
|
|
456
|
+
}
|
|
457
|
+
const parsedTransaction = await parseTransaction(params.transaction, params.networkId);
|
|
458
|
+
return await this.client.signAndSendTransaction(this.walletId, parsedTransaction.base64url, params.networkId);
|
|
459
|
+
}
|
|
460
|
+
getAddresses() {
|
|
461
|
+
return this.addresses;
|
|
462
|
+
}
|
|
463
|
+
isConnected() {
|
|
464
|
+
return this.client !== null && this.walletId !== null;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// src/ProviderManager.ts
|
|
469
|
+
var ProviderManager = class {
|
|
470
|
+
constructor(config) {
|
|
471
|
+
this.providers = /* @__PURE__ */ new Map();
|
|
472
|
+
this.currentProvider = null;
|
|
473
|
+
this.currentProviderKey = null;
|
|
474
|
+
this.walletId = null;
|
|
475
|
+
this.config = config;
|
|
476
|
+
this.setDefaultProvider();
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Switch to a different provider type
|
|
480
|
+
*/
|
|
481
|
+
switchProvider(type, options) {
|
|
482
|
+
if (options?.embeddedWalletType && !["app-wallet", "user-wallet"].includes(options.embeddedWalletType)) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`Invalid embeddedWalletType: ${options.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
const key = this.getProviderKey(type, options?.embeddedWalletType);
|
|
488
|
+
if (!this.providers.has(key)) {
|
|
489
|
+
this.createProvider(type, options?.embeddedWalletType);
|
|
490
|
+
}
|
|
491
|
+
this.currentProvider = this.providers.get(key);
|
|
492
|
+
this.currentProviderKey = key;
|
|
493
|
+
this.walletId = null;
|
|
494
|
+
return this.currentProvider;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Get the current active provider
|
|
498
|
+
*/
|
|
499
|
+
getCurrentProvider() {
|
|
500
|
+
return this.currentProvider;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Get current provider type and options
|
|
504
|
+
*/
|
|
505
|
+
getCurrentProviderInfo() {
|
|
506
|
+
if (!this.currentProviderKey)
|
|
507
|
+
return null;
|
|
508
|
+
const [type, embeddedWalletType] = this.currentProviderKey.split("-");
|
|
509
|
+
return {
|
|
510
|
+
type,
|
|
511
|
+
embeddedWalletType
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Connect using the current provider
|
|
516
|
+
*/
|
|
517
|
+
async connect() {
|
|
518
|
+
if (!this.currentProvider) {
|
|
519
|
+
throw new Error("No provider selected");
|
|
520
|
+
}
|
|
521
|
+
const result = await this.currentProvider.connect();
|
|
522
|
+
this.walletId = result.walletId || null;
|
|
523
|
+
this.saveProviderPreference();
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Disconnect from current provider
|
|
528
|
+
*/
|
|
529
|
+
async disconnect() {
|
|
530
|
+
if (!this.currentProvider)
|
|
531
|
+
return;
|
|
532
|
+
await this.currentProvider.disconnect();
|
|
533
|
+
this.walletId = null;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Sign a message using current provider
|
|
537
|
+
*/
|
|
538
|
+
async signMessage(params) {
|
|
539
|
+
if (!this.currentProvider) {
|
|
540
|
+
throw new Error("No provider connected");
|
|
541
|
+
}
|
|
542
|
+
return this.currentProvider.signMessage(params);
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Sign and send transaction using current provider
|
|
546
|
+
*/
|
|
547
|
+
async signAndSendTransaction(params) {
|
|
548
|
+
if (!this.currentProvider) {
|
|
549
|
+
throw new Error("No provider connected");
|
|
550
|
+
}
|
|
551
|
+
return this.currentProvider.signAndSendTransaction(params);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get addresses from current provider
|
|
555
|
+
*/
|
|
556
|
+
getAddresses() {
|
|
557
|
+
if (!this.currentProvider) {
|
|
558
|
+
return [];
|
|
559
|
+
}
|
|
560
|
+
return this.currentProvider.getAddresses();
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Check if current provider is connected
|
|
564
|
+
*/
|
|
565
|
+
isConnected() {
|
|
566
|
+
return this.currentProvider?.isConnected() ?? false;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Get current wallet ID
|
|
570
|
+
*/
|
|
571
|
+
getWalletId() {
|
|
572
|
+
return this.walletId;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Set default provider based on initial config
|
|
576
|
+
*/
|
|
577
|
+
setDefaultProvider() {
|
|
578
|
+
const defaultType = this.config.providerType || "embedded";
|
|
579
|
+
const defaultEmbeddedType = this.config.embeddedWalletType || "app-wallet";
|
|
580
|
+
this.createProvider(defaultType, defaultEmbeddedType);
|
|
581
|
+
this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Create a provider instance
|
|
585
|
+
*/
|
|
586
|
+
createProvider(type, embeddedWalletType) {
|
|
587
|
+
const key = this.getProviderKey(type, embeddedWalletType);
|
|
588
|
+
if (this.providers.has(key))
|
|
589
|
+
return;
|
|
590
|
+
let provider;
|
|
591
|
+
if (type === "injected") {
|
|
592
|
+
provider = new InjectedProvider({
|
|
593
|
+
solanaProvider: this.config.solanaProvider || "web3js",
|
|
594
|
+
addressTypes: this.config.addressTypes || []
|
|
595
|
+
});
|
|
596
|
+
} else {
|
|
597
|
+
if (!this.config.apiBaseUrl || !this.config.organizationId) {
|
|
598
|
+
throw new Error("apiBaseUrl and organizationId are required for embedded provider");
|
|
599
|
+
}
|
|
600
|
+
provider = new EmbeddedProvider({
|
|
601
|
+
apiBaseUrl: this.config.apiBaseUrl,
|
|
602
|
+
organizationId: this.config.organizationId,
|
|
603
|
+
authUrl: this.config.authUrl,
|
|
604
|
+
embeddedWalletType: embeddedWalletType || "app-wallet",
|
|
605
|
+
addressTypes: this.config.addressTypes || [],
|
|
606
|
+
solanaProvider: this.config.solanaProvider || "web3js"
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
this.providers.set(key, provider);
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Generate a unique key for provider instances
|
|
613
|
+
*/
|
|
614
|
+
getProviderKey(type, embeddedWalletType) {
|
|
615
|
+
if (type === "injected") {
|
|
616
|
+
return "injected";
|
|
617
|
+
}
|
|
618
|
+
return `embedded-${embeddedWalletType || "app-wallet"}`;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Save provider preference to localStorage
|
|
622
|
+
*/
|
|
623
|
+
saveProviderPreference() {
|
|
624
|
+
try {
|
|
625
|
+
const preference = this.getCurrentProviderInfo();
|
|
626
|
+
if (preference) {
|
|
627
|
+
localStorage.setItem("phantom-provider-preference", JSON.stringify(preference));
|
|
628
|
+
}
|
|
629
|
+
} catch (error) {
|
|
630
|
+
console.error("Failed to save provider preference:", error);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Restore provider preference from localStorage
|
|
635
|
+
*/
|
|
636
|
+
/*
|
|
637
|
+
private restoreProviderPreference(): void {
|
|
638
|
+
try {
|
|
639
|
+
const saved = localStorage.getItem("phantom-provider-preference");
|
|
640
|
+
if (saved) {
|
|
641
|
+
const preference: ProviderPreference = JSON.parse(saved);
|
|
642
|
+
this.switchProvider(preference.type, {
|
|
643
|
+
embeddedWalletType: preference.embeddedWalletType,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
} catch (error) {
|
|
647
|
+
// Ignore localStorage errors - just use default provider
|
|
648
|
+
console.error("Failed to restore provider preference:", error);
|
|
649
|
+
}
|
|
650
|
+
}*/
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// src/BrowserSDK.ts
|
|
654
|
+
var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
|
|
655
|
+
var BrowserSDK = class {
|
|
656
|
+
constructor(config) {
|
|
657
|
+
if (!["injected", "embedded"].includes(config.providerType)) {
|
|
658
|
+
throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
|
|
659
|
+
}
|
|
660
|
+
const embeddedWalletType = config.embeddedWalletType || "app-wallet";
|
|
661
|
+
if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
|
|
662
|
+
throw new Error(
|
|
663
|
+
`Invalid embeddedWalletType: ${config.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
config.embeddedWalletType = embeddedWalletType;
|
|
667
|
+
this.config = config;
|
|
668
|
+
this.providerManager = new ProviderManager(config);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Connect to the wallet with optional provider switching
|
|
672
|
+
*/
|
|
673
|
+
async connect(options) {
|
|
674
|
+
if (options?.providerType) {
|
|
675
|
+
if (!["injected", "embedded"].includes(options.providerType)) {
|
|
676
|
+
throw new Error(`Invalid providerType: ${options.providerType}. Must be "injected" or "embedded".`);
|
|
677
|
+
}
|
|
678
|
+
if (options.embeddedWalletType && !["app-wallet", "user-wallet"].includes(options.embeddedWalletType)) {
|
|
679
|
+
throw new Error(
|
|
680
|
+
`Invalid embeddedWalletType: ${options.embeddedWalletType}. Must be "app-wallet" or "user-wallet".`
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
await this.providerManager.switchProvider(options.providerType, {
|
|
684
|
+
embeddedWalletType: options.embeddedWalletType
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
return this.providerManager.connect();
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Switch to a different provider type
|
|
691
|
+
*/
|
|
692
|
+
async switchProvider(type, options) {
|
|
693
|
+
if (!["injected", "embedded"].includes(type)) {
|
|
694
|
+
throw new Error(`Invalid providerType: ${type}. Must be "injected" or "embedded".`);
|
|
695
|
+
}
|
|
696
|
+
await this.providerManager.switchProvider(type, options);
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Get current provider information
|
|
700
|
+
*/
|
|
701
|
+
getCurrentProviderInfo() {
|
|
702
|
+
return this.providerManager.getCurrentProviderInfo();
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Wait for Phantom extension to become available
|
|
706
|
+
*/
|
|
707
|
+
async waitForPhantomExtension(timeoutMs) {
|
|
708
|
+
const isInstalled = async (retries = 3, timeAccumulated = 0) => {
|
|
709
|
+
const installed = (0, import_browser_injected_sdk2.isPhantomExtensionInstalled)();
|
|
710
|
+
if (installed)
|
|
711
|
+
return true;
|
|
712
|
+
if (retries <= 0)
|
|
713
|
+
return false;
|
|
714
|
+
if (timeAccumulated >= (timeoutMs || 3e3))
|
|
715
|
+
return false;
|
|
716
|
+
return new Promise((resolve) => {
|
|
717
|
+
setTimeout(async () => {
|
|
718
|
+
const result = await isInstalled(retries - 1, timeAccumulated + 100);
|
|
719
|
+
resolve(result);
|
|
720
|
+
}, 100);
|
|
721
|
+
});
|
|
722
|
+
};
|
|
723
|
+
return isInstalled();
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Disconnect from the wallet
|
|
727
|
+
*/
|
|
728
|
+
async disconnect() {
|
|
729
|
+
return this.providerManager.disconnect();
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Sign a message
|
|
733
|
+
* @param message - Message string to sign
|
|
734
|
+
* @param networkId - Network identifier
|
|
735
|
+
* @returns Signature string
|
|
736
|
+
*/
|
|
737
|
+
async signMessage(params) {
|
|
738
|
+
return this.providerManager.signMessage(params);
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Sign and send a transaction
|
|
742
|
+
* @param params - Transaction parameters with native transaction object
|
|
743
|
+
* @returns Transaction result
|
|
744
|
+
*/
|
|
745
|
+
async signAndSendTransaction(params) {
|
|
746
|
+
return this.providerManager.signAndSendTransaction(params);
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Get wallet addresses
|
|
750
|
+
*/
|
|
751
|
+
getAddresses() {
|
|
752
|
+
return this.providerManager.getAddresses();
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Check if wallet is connected
|
|
756
|
+
*/
|
|
757
|
+
isConnected() {
|
|
758
|
+
return this.providerManager.isConnected();
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Get the current wallet ID (for embedded wallets)
|
|
762
|
+
*/
|
|
763
|
+
getWalletId() {
|
|
764
|
+
return this.providerManager.getWalletId();
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Create a user organization via your backend API
|
|
768
|
+
* @param params - Parameters including userId and any additional options
|
|
769
|
+
* @returns Organization creation result with organizationId
|
|
770
|
+
*/
|
|
771
|
+
async createUserOrganization(params) {
|
|
772
|
+
if (!this.config.serverUrl) {
|
|
773
|
+
throw new Error("serverUrl is required in config to create user organizations");
|
|
774
|
+
}
|
|
775
|
+
try {
|
|
776
|
+
const response = await fetch(`${this.config.serverUrl}/organizations`, {
|
|
777
|
+
method: "POST",
|
|
778
|
+
headers: {
|
|
779
|
+
"Content-Type": "application/json"
|
|
780
|
+
},
|
|
781
|
+
body: JSON.stringify(params)
|
|
782
|
+
});
|
|
783
|
+
if (!response.ok) {
|
|
784
|
+
throw new Error(`Failed to create organization: ${response.status} ${response.statusText}`);
|
|
785
|
+
}
|
|
786
|
+
const result = await response.json();
|
|
787
|
+
return result;
|
|
788
|
+
} catch (error) {
|
|
789
|
+
throw new Error(`Error creating user organization: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
// src/index.ts
|
|
795
|
+
var import_client3 = require("@phantom/client");
|