@phantom/browser-sdk 0.2.3 → 0.3.1
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 +50 -21
- package/dist/index.d.ts +34 -6
- package/dist/index.js +174 -10
- package/dist/index.mjs +164 -10
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ import { BrowserSDK, AddressType, NetworkId } from "@phantom/browser-sdk";
|
|
|
37
37
|
const sdk = new BrowserSDK({
|
|
38
38
|
providerType: "embedded",
|
|
39
39
|
addressTypes: [AddressType.solana, AddressType.ethereum],
|
|
40
|
-
apiBaseUrl: "https://api.phantom.
|
|
40
|
+
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
41
41
|
organizationId: "your-org-id",
|
|
42
42
|
});
|
|
43
43
|
|
|
@@ -80,7 +80,7 @@ Creates a non-custodial wallet embedded in your application. Requires API config
|
|
|
80
80
|
const sdk = new BrowserSDK({
|
|
81
81
|
providerType: "embedded",
|
|
82
82
|
addressTypes: [AddressType.solana, AddressType.ethereum],
|
|
83
|
-
apiBaseUrl: "https://api.phantom.
|
|
83
|
+
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
84
84
|
organizationId: "your-org-id",
|
|
85
85
|
embeddedWalletType: "app-wallet", // or 'user-wallet'
|
|
86
86
|
authOptions: {
|
|
@@ -237,7 +237,6 @@ const result = await sdk.connect({
|
|
|
237
237
|
**Authentication Flow Types:**
|
|
238
238
|
|
|
239
239
|
1. **Phantom Connect (Redirect-based)**: Used when `provider` is undefined, `"google"`, or `"apple"`
|
|
240
|
-
|
|
241
240
|
- Redirects to `https://connect.phantom.app` (or custom `authOptions.authUrl` from config)
|
|
242
241
|
- Handles OAuth flow with selected provider
|
|
243
242
|
- Returns to your app with authentication result using `authOptions.redirectUrl` or current page
|
|
@@ -317,17 +316,35 @@ npm install @solana/web3.js
|
|
|
317
316
|
```
|
|
318
317
|
|
|
319
318
|
```typescript
|
|
320
|
-
import {
|
|
319
|
+
import {
|
|
320
|
+
VersionedTransaction,
|
|
321
|
+
TransactionMessage,
|
|
322
|
+
SystemProgram,
|
|
323
|
+
PublicKey,
|
|
324
|
+
LAMPORTS_PER_SOL,
|
|
325
|
+
Connection,
|
|
326
|
+
} from "@solana/web3.js";
|
|
321
327
|
import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
|
|
322
328
|
|
|
323
|
-
//
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
)
|
|
329
|
+
// Get recent blockhash
|
|
330
|
+
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
|
331
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
332
|
+
|
|
333
|
+
// Create transfer instruction
|
|
334
|
+
const transferInstruction = SystemProgram.transfer({
|
|
335
|
+
fromPubkey: new PublicKey(fromAddress),
|
|
336
|
+
toPubkey: new PublicKey(toAddress),
|
|
337
|
+
lamports: 0.001 * LAMPORTS_PER_SOL,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Create VersionedTransaction
|
|
341
|
+
const messageV0 = new TransactionMessage({
|
|
342
|
+
payerKey: new PublicKey(fromAddress),
|
|
343
|
+
recentBlockhash: blockhash,
|
|
344
|
+
instructions: [transferInstruction],
|
|
345
|
+
}).compileToV0Message();
|
|
346
|
+
|
|
347
|
+
const transaction = new VersionedTransaction(messageV0);
|
|
331
348
|
|
|
332
349
|
// Send native transaction object - no encoding needed!
|
|
333
350
|
const result = await sdk.signAndSendTransaction({
|
|
@@ -553,19 +570,31 @@ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
|
|
|
553
570
|
|
|
554
571
|
const sdk = new BrowserSDK({
|
|
555
572
|
addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui],
|
|
556
|
-
apiBaseUrl: "https://api.phantom.
|
|
573
|
+
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
557
574
|
organizationId: "your-org-id",
|
|
558
575
|
});
|
|
559
576
|
|
|
560
577
|
class MultiChainWallet {
|
|
561
578
|
async sendSolana(amount: number, recipient: string) {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
579
|
+
// Get recent blockhash
|
|
580
|
+
const connection = new Connection("https://api.mainnet-beta.solana.com");
|
|
581
|
+
const { blockhash } = await connection.getLatestBlockhash();
|
|
582
|
+
|
|
583
|
+
// Create transfer instruction
|
|
584
|
+
const transferInstruction = SystemProgram.transfer({
|
|
585
|
+
fromPubkey: new PublicKey(this.solanaAddress),
|
|
586
|
+
toPubkey: new PublicKey(recipient),
|
|
587
|
+
lamports: amount * LAMPORTS_PER_SOL,
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
// Create VersionedTransaction
|
|
591
|
+
const messageV0 = new TransactionMessage({
|
|
592
|
+
payerKey: new PublicKey(this.solanaAddress),
|
|
593
|
+
recentBlockhash: blockhash,
|
|
594
|
+
instructions: [transferInstruction],
|
|
595
|
+
}).compileToV0Message();
|
|
596
|
+
|
|
597
|
+
const transaction = new VersionedTransaction(messageV0);
|
|
569
598
|
|
|
570
599
|
return await sdk.signAndSendTransaction({
|
|
571
600
|
networkId: NetworkId.SOLANA_MAINNET,
|
|
@@ -728,7 +757,7 @@ For embedded wallets, you need to set up a backend endpoint. Add the `serverUrl`
|
|
|
728
757
|
const sdk = new BrowserSDK({
|
|
729
758
|
providerType: "embedded",
|
|
730
759
|
addressTypes: [AddressType.solana],
|
|
731
|
-
apiBaseUrl: "https://api.phantom.
|
|
760
|
+
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
732
761
|
organizationId: "your-org-id",
|
|
733
762
|
serverUrl: "http://localhost:3000/api",
|
|
734
763
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AddressType } from '@phantom/client';
|
|
2
|
-
export { AddressType
|
|
3
|
-
import { AuthOptions, ConnectResult, SignMessageParams, SignAndSendTransactionParams, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
4
|
-
export { AuthOptions, ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
2
|
+
export { AddressType } from '@phantom/client';
|
|
3
|
+
import { AuthOptions, ConnectResult, SignMessageParams, SignMessageResult, SignAndSendTransactionParams, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
4
|
+
export { AuthOptions, ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
5
|
+
export { NetworkId } from '@phantom/constants';
|
|
5
6
|
|
|
6
7
|
declare enum DebugLevel {
|
|
7
8
|
ERROR = 0,
|
|
@@ -77,7 +78,7 @@ interface CreateUserOrganizationResult {
|
|
|
77
78
|
interface Provider {
|
|
78
79
|
connect(authOptions?: AuthOptions): Promise<ConnectResult>;
|
|
79
80
|
disconnect(): Promise<void>;
|
|
80
|
-
signMessage(params: SignMessageParams): Promise<
|
|
81
|
+
signMessage(params: SignMessageParams): Promise<SignMessageResult>;
|
|
81
82
|
signAndSendTransaction(params: SignAndSendTransactionParams): Promise<SignedTransaction>;
|
|
82
83
|
getAddresses(): WalletAddress[];
|
|
83
84
|
isConnected(): boolean;
|
|
@@ -125,7 +126,7 @@ declare class BrowserSDK {
|
|
|
125
126
|
* @param networkId - Network identifier
|
|
126
127
|
* @returns Signature string
|
|
127
128
|
*/
|
|
128
|
-
signMessage(params: SignMessageParams): Promise<
|
|
129
|
+
signMessage(params: SignMessageParams): Promise<SignMessageResult>;
|
|
129
130
|
/**
|
|
130
131
|
* Sign and send a transaction
|
|
131
132
|
* @param params - Transaction parameters with native transaction object
|
|
@@ -158,4 +159,31 @@ declare class BrowserSDK {
|
|
|
158
159
|
declare const DEFAULT_AUTH_URL = "https://connect.phantom.app";
|
|
159
160
|
declare const DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
|
|
160
161
|
|
|
161
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Browser detection utility to identify browser name and version
|
|
164
|
+
*/
|
|
165
|
+
interface BrowserInfo {
|
|
166
|
+
name: string;
|
|
167
|
+
version: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Parse browser information from a user agent string
|
|
171
|
+
* This is the core parsing logic that can be unit tested independently
|
|
172
|
+
*/
|
|
173
|
+
declare function parseBrowserFromUserAgent(userAgent: string, hasBraveAPI?: boolean): BrowserInfo;
|
|
174
|
+
/**
|
|
175
|
+
* Detect the current browser and version from the user agent string
|
|
176
|
+
*/
|
|
177
|
+
declare function detectBrowser(): BrowserInfo;
|
|
178
|
+
/**
|
|
179
|
+
* Get a formatted platform name for use in authenticator names
|
|
180
|
+
* Format: "browsername-v123" (e.g., "chrome-v120", "firefox-v119")
|
|
181
|
+
*/
|
|
182
|
+
declare function getPlatformName(): string;
|
|
183
|
+
/**
|
|
184
|
+
* Get detailed browser information as a string
|
|
185
|
+
* Format: "Chrome 120.0" or "Firefox 119.0"
|
|
186
|
+
*/
|
|
187
|
+
declare function getBrowserDisplayName(): string;
|
|
188
|
+
|
|
189
|
+
export { BrowserInfo, BrowserSDK, BrowserSDKConfig, CreateUserOrganizationParams, CreateUserOrganizationResult, DEFAULT_AUTH_URL, DEFAULT_WALLET_API_URL, DebugCallback, DebugCategory, DebugLevel, DebugMessage, Provider, debug, detectBrowser, getBrowserDisplayName, getPlatformName, parseBrowserFromUserAgent };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -26,8 +36,12 @@ __export(src_exports, {
|
|
|
26
36
|
DEFAULT_WALLET_API_URL: () => DEFAULT_WALLET_API_URL,
|
|
27
37
|
DebugCategory: () => DebugCategory,
|
|
28
38
|
DebugLevel: () => DebugLevel,
|
|
29
|
-
NetworkId: () =>
|
|
30
|
-
debug: () => debug
|
|
39
|
+
NetworkId: () => import_constants3.NetworkId,
|
|
40
|
+
debug: () => debug,
|
|
41
|
+
detectBrowser: () => detectBrowser,
|
|
42
|
+
getBrowserDisplayName: () => getBrowserDisplayName,
|
|
43
|
+
getPlatformName: () => getPlatformName,
|
|
44
|
+
parseBrowserFromUserAgent: () => parseBrowserFromUserAgent
|
|
31
45
|
});
|
|
32
46
|
module.exports = __toCommonJS(src_exports);
|
|
33
47
|
|
|
@@ -112,6 +126,9 @@ var DebugCategory = {
|
|
|
112
126
|
};
|
|
113
127
|
|
|
114
128
|
// src/providers/injected/index.ts
|
|
129
|
+
var import_base64url = require("@phantom/base64url");
|
|
130
|
+
var import_constants = require("@phantom/constants");
|
|
131
|
+
var import_bs58 = __toESM(require("bs58"));
|
|
115
132
|
var InjectedProvider = class {
|
|
116
133
|
constructor(config) {
|
|
117
134
|
this.connected = false;
|
|
@@ -210,18 +227,24 @@ var InjectedProvider = class {
|
|
|
210
227
|
throw new Error("Wallet not connected");
|
|
211
228
|
}
|
|
212
229
|
const networkPrefix = params.networkId.split(":")[0].toLowerCase();
|
|
230
|
+
let signatureResult;
|
|
213
231
|
if (networkPrefix === "solana") {
|
|
214
232
|
const { signature } = await this.phantom.solana.signMessage(new TextEncoder().encode(params.message));
|
|
215
|
-
|
|
233
|
+
signatureResult = import_bs58.default.encode(signature);
|
|
216
234
|
} else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
|
|
217
235
|
const address = this.addresses.find((addr) => addr.addressType === import_client.AddressType.ethereum)?.address;
|
|
218
236
|
if (!address) {
|
|
219
237
|
throw new Error("No address available");
|
|
220
238
|
}
|
|
221
239
|
const signature = await this.phantom.ethereum.signPersonalMessage(params.message, address);
|
|
222
|
-
|
|
240
|
+
signatureResult = signature;
|
|
241
|
+
} else {
|
|
242
|
+
throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
|
|
223
243
|
}
|
|
224
|
-
|
|
244
|
+
return {
|
|
245
|
+
signature: signatureResult,
|
|
246
|
+
rawSignature: (0, import_base64url.base64urlEncode)(signatureResult)
|
|
247
|
+
};
|
|
225
248
|
}
|
|
226
249
|
async signAndSendTransaction(params) {
|
|
227
250
|
if (!this.connected) {
|
|
@@ -232,7 +255,9 @@ var InjectedProvider = class {
|
|
|
232
255
|
const transaction = params.transaction;
|
|
233
256
|
const result = await this.phantom.solana.signAndSendTransaction(transaction);
|
|
234
257
|
return {
|
|
235
|
-
|
|
258
|
+
hash: result.signature,
|
|
259
|
+
rawTransaction: (0, import_base64url.base64urlEncode)(result.signature),
|
|
260
|
+
blockExplorer: (0, import_constants.getExplorerUrl)(params.networkId, "transaction", result.signature)
|
|
236
261
|
};
|
|
237
262
|
} else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
|
|
238
263
|
const toHex = (value) => {
|
|
@@ -255,7 +280,9 @@ var InjectedProvider = class {
|
|
|
255
280
|
};
|
|
256
281
|
const txHash = await this.phantom.ethereum.sendTransaction(txRequest);
|
|
257
282
|
return {
|
|
258
|
-
|
|
283
|
+
hash: txHash,
|
|
284
|
+
rawTransaction: (0, import_base64url.base64urlEncode)(txHash),
|
|
285
|
+
blockExplorer: (0, import_constants.getExplorerUrl)(params.networkId, "transaction", txHash)
|
|
259
286
|
};
|
|
260
287
|
}
|
|
261
288
|
throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
|
|
@@ -270,6 +297,7 @@ var InjectedProvider = class {
|
|
|
270
297
|
|
|
271
298
|
// src/providers/embedded/index.ts
|
|
272
299
|
var import_embedded_provider_core = require("@phantom/embedded-provider-core");
|
|
300
|
+
var import_indexed_db_stamper = require("@phantom/indexed-db-stamper");
|
|
273
301
|
|
|
274
302
|
// src/providers/embedded/adapters/storage.ts
|
|
275
303
|
var BrowserStorage = class {
|
|
@@ -495,16 +523,133 @@ var BrowserLogger = class {
|
|
|
495
523
|
}
|
|
496
524
|
};
|
|
497
525
|
|
|
526
|
+
// src/utils/browser-detection.ts
|
|
527
|
+
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
528
|
+
let name = "unknown";
|
|
529
|
+
let version = "unknown";
|
|
530
|
+
if (!userAgent || typeof userAgent !== "string") {
|
|
531
|
+
return { name, version };
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
if (userAgent.includes("Edg/")) {
|
|
535
|
+
name = "edge";
|
|
536
|
+
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
537
|
+
if (match)
|
|
538
|
+
version = match[1].split(".")[0];
|
|
539
|
+
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
540
|
+
name = "opera";
|
|
541
|
+
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
542
|
+
if (match)
|
|
543
|
+
version = match[1].split(".")[0];
|
|
544
|
+
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
545
|
+
name = "samsung";
|
|
546
|
+
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
547
|
+
if (match)
|
|
548
|
+
version = match[1].split(".")[0];
|
|
549
|
+
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
550
|
+
name = "duckduckgo";
|
|
551
|
+
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
552
|
+
if (match)
|
|
553
|
+
version = match[1].split(".")[0];
|
|
554
|
+
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
555
|
+
name = "brave";
|
|
556
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
557
|
+
if (match)
|
|
558
|
+
version = match[1].split(".")[0];
|
|
559
|
+
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
560
|
+
if (userAgent.includes("Chrome/")) {
|
|
561
|
+
name = "chrome-mobile";
|
|
562
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
563
|
+
if (match)
|
|
564
|
+
version = match[1].split(".")[0];
|
|
565
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
566
|
+
name = "firefox-mobile";
|
|
567
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
568
|
+
if (match)
|
|
569
|
+
version = match[1].split(".")[0];
|
|
570
|
+
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
571
|
+
name = "safari-mobile";
|
|
572
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
573
|
+
if (match)
|
|
574
|
+
version = match[1].split(".")[0];
|
|
575
|
+
} else {
|
|
576
|
+
name = "mobile";
|
|
577
|
+
}
|
|
578
|
+
} else if (userAgent.includes("Chrome/")) {
|
|
579
|
+
name = "chrome";
|
|
580
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
581
|
+
if (match)
|
|
582
|
+
version = match[1].split(".")[0];
|
|
583
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
584
|
+
name = "firefox";
|
|
585
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
586
|
+
if (match)
|
|
587
|
+
version = match[1].split(".")[0];
|
|
588
|
+
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
589
|
+
name = "safari";
|
|
590
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
591
|
+
if (match)
|
|
592
|
+
version = match[1].split(".")[0];
|
|
593
|
+
}
|
|
594
|
+
if (name === "unknown") {
|
|
595
|
+
const patterns = [
|
|
596
|
+
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
597
|
+
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
598
|
+
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
599
|
+
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
600
|
+
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
601
|
+
];
|
|
602
|
+
for (const pattern of patterns) {
|
|
603
|
+
const match = userAgent.match(pattern.regex);
|
|
604
|
+
if (match) {
|
|
605
|
+
name = pattern.name;
|
|
606
|
+
version = match[1];
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
} catch (error) {
|
|
612
|
+
}
|
|
613
|
+
return { name, version };
|
|
614
|
+
}
|
|
615
|
+
function detectBrowser() {
|
|
616
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
617
|
+
return { name: "unknown", version: "unknown" };
|
|
618
|
+
}
|
|
619
|
+
const userAgent = window.navigator.userAgent;
|
|
620
|
+
const hasBraveAPI = !!navigator.brave;
|
|
621
|
+
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
622
|
+
}
|
|
623
|
+
function getPlatformName() {
|
|
624
|
+
const { name, version } = detectBrowser();
|
|
625
|
+
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
626
|
+
}
|
|
627
|
+
function getBrowserDisplayName() {
|
|
628
|
+
const { name, version } = detectBrowser();
|
|
629
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
630
|
+
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
631
|
+
}
|
|
632
|
+
|
|
498
633
|
// src/providers/embedded/index.ts
|
|
499
634
|
var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
|
|
500
635
|
constructor(config) {
|
|
501
636
|
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
|
|
502
637
|
const urlParamsAccessor = new BrowserURLParamsAccessor();
|
|
638
|
+
const stamper = new import_indexed_db_stamper.IndexedDbStamper({
|
|
639
|
+
dbName: `phantom-embedded-sdk-${config.organizationId}`,
|
|
640
|
+
storeName: "crypto-keys",
|
|
641
|
+
keyName: "signing-key"
|
|
642
|
+
});
|
|
643
|
+
const platformName = getPlatformName();
|
|
503
644
|
const platform = {
|
|
504
645
|
storage: new BrowserStorage(),
|
|
505
646
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
506
|
-
urlParamsAccessor
|
|
647
|
+
urlParamsAccessor,
|
|
648
|
+
stamper,
|
|
649
|
+
name: platformName
|
|
650
|
+
// Use detected browser name and version for identification
|
|
507
651
|
};
|
|
652
|
+
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
|
|
508
653
|
const logger = new BrowserLogger();
|
|
509
654
|
super(config, platform, logger);
|
|
510
655
|
debug.info(DebugCategory.EMBEDDED_PROVIDER, "Browser EmbeddedProvider initialized");
|
|
@@ -841,7 +986,17 @@ var BrowserSDK = class {
|
|
|
841
986
|
* @returns Signature string
|
|
842
987
|
*/
|
|
843
988
|
async signMessage(params) {
|
|
844
|
-
|
|
989
|
+
debug.info(DebugCategory.BROWSER_SDK, "Signing message", {
|
|
990
|
+
message: params.message,
|
|
991
|
+
networkId: params.networkId
|
|
992
|
+
});
|
|
993
|
+
const result = await this.providerManager.signMessage(params);
|
|
994
|
+
debug.info(DebugCategory.BROWSER_SDK, "Message signed successfully", {
|
|
995
|
+
message: params.message,
|
|
996
|
+
networkId: params.networkId,
|
|
997
|
+
result
|
|
998
|
+
});
|
|
999
|
+
return result;
|
|
845
1000
|
}
|
|
846
1001
|
/**
|
|
847
1002
|
* Sign and send a transaction
|
|
@@ -849,7 +1004,15 @@ var BrowserSDK = class {
|
|
|
849
1004
|
* @returns Transaction result
|
|
850
1005
|
*/
|
|
851
1006
|
async signAndSendTransaction(params) {
|
|
852
|
-
|
|
1007
|
+
debug.info(DebugCategory.BROWSER_SDK, "Signing and sending transaction", {
|
|
1008
|
+
networkId: params.networkId
|
|
1009
|
+
});
|
|
1010
|
+
const result = await this.providerManager.signAndSendTransaction(params);
|
|
1011
|
+
debug.info(DebugCategory.BROWSER_SDK, "Transaction signed and sent successfully", {
|
|
1012
|
+
networkId: params.networkId,
|
|
1013
|
+
result
|
|
1014
|
+
});
|
|
1015
|
+
return result;
|
|
853
1016
|
}
|
|
854
1017
|
/**
|
|
855
1018
|
* Get wallet addresses
|
|
@@ -898,4 +1061,5 @@ var BrowserSDK = class {
|
|
|
898
1061
|
};
|
|
899
1062
|
|
|
900
1063
|
// src/index.ts
|
|
1064
|
+
var import_constants3 = require("@phantom/constants");
|
|
901
1065
|
var import_client2 = require("@phantom/client");
|
package/dist/index.mjs
CHANGED
|
@@ -79,6 +79,9 @@ var DebugCategory = {
|
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
// src/providers/injected/index.ts
|
|
82
|
+
import { base64urlEncode } from "@phantom/base64url";
|
|
83
|
+
import { getExplorerUrl } from "@phantom/constants";
|
|
84
|
+
import bs58 from "bs58";
|
|
82
85
|
var InjectedProvider = class {
|
|
83
86
|
constructor(config) {
|
|
84
87
|
this.connected = false;
|
|
@@ -177,18 +180,24 @@ var InjectedProvider = class {
|
|
|
177
180
|
throw new Error("Wallet not connected");
|
|
178
181
|
}
|
|
179
182
|
const networkPrefix = params.networkId.split(":")[0].toLowerCase();
|
|
183
|
+
let signatureResult;
|
|
180
184
|
if (networkPrefix === "solana") {
|
|
181
185
|
const { signature } = await this.phantom.solana.signMessage(new TextEncoder().encode(params.message));
|
|
182
|
-
|
|
186
|
+
signatureResult = bs58.encode(signature);
|
|
183
187
|
} else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
|
|
184
188
|
const address = this.addresses.find((addr) => addr.addressType === AddressType.ethereum)?.address;
|
|
185
189
|
if (!address) {
|
|
186
190
|
throw new Error("No address available");
|
|
187
191
|
}
|
|
188
192
|
const signature = await this.phantom.ethereum.signPersonalMessage(params.message, address);
|
|
189
|
-
|
|
193
|
+
signatureResult = signature;
|
|
194
|
+
} else {
|
|
195
|
+
throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
|
|
190
196
|
}
|
|
191
|
-
|
|
197
|
+
return {
|
|
198
|
+
signature: signatureResult,
|
|
199
|
+
rawSignature: base64urlEncode(signatureResult)
|
|
200
|
+
};
|
|
192
201
|
}
|
|
193
202
|
async signAndSendTransaction(params) {
|
|
194
203
|
if (!this.connected) {
|
|
@@ -199,7 +208,9 @@ var InjectedProvider = class {
|
|
|
199
208
|
const transaction = params.transaction;
|
|
200
209
|
const result = await this.phantom.solana.signAndSendTransaction(transaction);
|
|
201
210
|
return {
|
|
202
|
-
|
|
211
|
+
hash: result.signature,
|
|
212
|
+
rawTransaction: base64urlEncode(result.signature),
|
|
213
|
+
blockExplorer: getExplorerUrl(params.networkId, "transaction", result.signature)
|
|
203
214
|
};
|
|
204
215
|
} else if (networkPrefix === "ethereum" || networkPrefix === "polygon" || networkPrefix === "eip155") {
|
|
205
216
|
const toHex = (value) => {
|
|
@@ -222,7 +233,9 @@ var InjectedProvider = class {
|
|
|
222
233
|
};
|
|
223
234
|
const txHash = await this.phantom.ethereum.sendTransaction(txRequest);
|
|
224
235
|
return {
|
|
225
|
-
|
|
236
|
+
hash: txHash,
|
|
237
|
+
rawTransaction: base64urlEncode(txHash),
|
|
238
|
+
blockExplorer: getExplorerUrl(params.networkId, "transaction", txHash)
|
|
226
239
|
};
|
|
227
240
|
}
|
|
228
241
|
throw new Error(`Network ${params.networkId} is not supported for injected wallets`);
|
|
@@ -237,6 +250,7 @@ var InjectedProvider = class {
|
|
|
237
250
|
|
|
238
251
|
// src/providers/embedded/index.ts
|
|
239
252
|
import { EmbeddedProvider as CoreEmbeddedProvider } from "@phantom/embedded-provider-core";
|
|
253
|
+
import { IndexedDbStamper } from "@phantom/indexed-db-stamper";
|
|
240
254
|
|
|
241
255
|
// src/providers/embedded/adapters/storage.ts
|
|
242
256
|
var BrowserStorage = class {
|
|
@@ -462,16 +476,133 @@ var BrowserLogger = class {
|
|
|
462
476
|
}
|
|
463
477
|
};
|
|
464
478
|
|
|
479
|
+
// src/utils/browser-detection.ts
|
|
480
|
+
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
481
|
+
let name = "unknown";
|
|
482
|
+
let version = "unknown";
|
|
483
|
+
if (!userAgent || typeof userAgent !== "string") {
|
|
484
|
+
return { name, version };
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
if (userAgent.includes("Edg/")) {
|
|
488
|
+
name = "edge";
|
|
489
|
+
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
490
|
+
if (match)
|
|
491
|
+
version = match[1].split(".")[0];
|
|
492
|
+
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
493
|
+
name = "opera";
|
|
494
|
+
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
495
|
+
if (match)
|
|
496
|
+
version = match[1].split(".")[0];
|
|
497
|
+
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
498
|
+
name = "samsung";
|
|
499
|
+
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
500
|
+
if (match)
|
|
501
|
+
version = match[1].split(".")[0];
|
|
502
|
+
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
503
|
+
name = "duckduckgo";
|
|
504
|
+
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
505
|
+
if (match)
|
|
506
|
+
version = match[1].split(".")[0];
|
|
507
|
+
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
508
|
+
name = "brave";
|
|
509
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
510
|
+
if (match)
|
|
511
|
+
version = match[1].split(".")[0];
|
|
512
|
+
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
513
|
+
if (userAgent.includes("Chrome/")) {
|
|
514
|
+
name = "chrome-mobile";
|
|
515
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
516
|
+
if (match)
|
|
517
|
+
version = match[1].split(".")[0];
|
|
518
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
519
|
+
name = "firefox-mobile";
|
|
520
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
521
|
+
if (match)
|
|
522
|
+
version = match[1].split(".")[0];
|
|
523
|
+
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
524
|
+
name = "safari-mobile";
|
|
525
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
526
|
+
if (match)
|
|
527
|
+
version = match[1].split(".")[0];
|
|
528
|
+
} else {
|
|
529
|
+
name = "mobile";
|
|
530
|
+
}
|
|
531
|
+
} else if (userAgent.includes("Chrome/")) {
|
|
532
|
+
name = "chrome";
|
|
533
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
534
|
+
if (match)
|
|
535
|
+
version = match[1].split(".")[0];
|
|
536
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
537
|
+
name = "firefox";
|
|
538
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
539
|
+
if (match)
|
|
540
|
+
version = match[1].split(".")[0];
|
|
541
|
+
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
542
|
+
name = "safari";
|
|
543
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
544
|
+
if (match)
|
|
545
|
+
version = match[1].split(".")[0];
|
|
546
|
+
}
|
|
547
|
+
if (name === "unknown") {
|
|
548
|
+
const patterns = [
|
|
549
|
+
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
550
|
+
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
551
|
+
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
552
|
+
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
553
|
+
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
554
|
+
];
|
|
555
|
+
for (const pattern of patterns) {
|
|
556
|
+
const match = userAgent.match(pattern.regex);
|
|
557
|
+
if (match) {
|
|
558
|
+
name = pattern.name;
|
|
559
|
+
version = match[1];
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
} catch (error) {
|
|
565
|
+
}
|
|
566
|
+
return { name, version };
|
|
567
|
+
}
|
|
568
|
+
function detectBrowser() {
|
|
569
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
570
|
+
return { name: "unknown", version: "unknown" };
|
|
571
|
+
}
|
|
572
|
+
const userAgent = window.navigator.userAgent;
|
|
573
|
+
const hasBraveAPI = !!navigator.brave;
|
|
574
|
+
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
575
|
+
}
|
|
576
|
+
function getPlatformName() {
|
|
577
|
+
const { name, version } = detectBrowser();
|
|
578
|
+
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
579
|
+
}
|
|
580
|
+
function getBrowserDisplayName() {
|
|
581
|
+
const { name, version } = detectBrowser();
|
|
582
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
583
|
+
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
584
|
+
}
|
|
585
|
+
|
|
465
586
|
// src/providers/embedded/index.ts
|
|
466
587
|
var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
467
588
|
constructor(config) {
|
|
468
589
|
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
|
|
469
590
|
const urlParamsAccessor = new BrowserURLParamsAccessor();
|
|
591
|
+
const stamper = new IndexedDbStamper({
|
|
592
|
+
dbName: `phantom-embedded-sdk-${config.organizationId}`,
|
|
593
|
+
storeName: "crypto-keys",
|
|
594
|
+
keyName: "signing-key"
|
|
595
|
+
});
|
|
596
|
+
const platformName = getPlatformName();
|
|
470
597
|
const platform = {
|
|
471
598
|
storage: new BrowserStorage(),
|
|
472
599
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
473
|
-
urlParamsAccessor
|
|
600
|
+
urlParamsAccessor,
|
|
601
|
+
stamper,
|
|
602
|
+
name: platformName
|
|
603
|
+
// Use detected browser name and version for identification
|
|
474
604
|
};
|
|
605
|
+
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
|
|
475
606
|
const logger = new BrowserLogger();
|
|
476
607
|
super(config, platform, logger);
|
|
477
608
|
debug.info(DebugCategory.EMBEDDED_PROVIDER, "Browser EmbeddedProvider initialized");
|
|
@@ -808,7 +939,17 @@ var BrowserSDK = class {
|
|
|
808
939
|
* @returns Signature string
|
|
809
940
|
*/
|
|
810
941
|
async signMessage(params) {
|
|
811
|
-
|
|
942
|
+
debug.info(DebugCategory.BROWSER_SDK, "Signing message", {
|
|
943
|
+
message: params.message,
|
|
944
|
+
networkId: params.networkId
|
|
945
|
+
});
|
|
946
|
+
const result = await this.providerManager.signMessage(params);
|
|
947
|
+
debug.info(DebugCategory.BROWSER_SDK, "Message signed successfully", {
|
|
948
|
+
message: params.message,
|
|
949
|
+
networkId: params.networkId,
|
|
950
|
+
result
|
|
951
|
+
});
|
|
952
|
+
return result;
|
|
812
953
|
}
|
|
813
954
|
/**
|
|
814
955
|
* Sign and send a transaction
|
|
@@ -816,7 +957,15 @@ var BrowserSDK = class {
|
|
|
816
957
|
* @returns Transaction result
|
|
817
958
|
*/
|
|
818
959
|
async signAndSendTransaction(params) {
|
|
819
|
-
|
|
960
|
+
debug.info(DebugCategory.BROWSER_SDK, "Signing and sending transaction", {
|
|
961
|
+
networkId: params.networkId
|
|
962
|
+
});
|
|
963
|
+
const result = await this.providerManager.signAndSendTransaction(params);
|
|
964
|
+
debug.info(DebugCategory.BROWSER_SDK, "Transaction signed and sent successfully", {
|
|
965
|
+
networkId: params.networkId,
|
|
966
|
+
result
|
|
967
|
+
});
|
|
968
|
+
return result;
|
|
820
969
|
}
|
|
821
970
|
/**
|
|
822
971
|
* Get wallet addresses
|
|
@@ -865,7 +1014,8 @@ var BrowserSDK = class {
|
|
|
865
1014
|
};
|
|
866
1015
|
|
|
867
1016
|
// src/index.ts
|
|
868
|
-
import { NetworkId
|
|
1017
|
+
import { NetworkId } from "@phantom/constants";
|
|
1018
|
+
import { AddressType as AddressType2 } from "@phantom/client";
|
|
869
1019
|
export {
|
|
870
1020
|
AddressType2 as AddressType,
|
|
871
1021
|
BrowserSDK,
|
|
@@ -874,5 +1024,9 @@ export {
|
|
|
874
1024
|
DebugCategory,
|
|
875
1025
|
DebugLevel,
|
|
876
1026
|
NetworkId,
|
|
877
|
-
debug
|
|
1027
|
+
debug,
|
|
1028
|
+
detectBrowser,
|
|
1029
|
+
getBrowserDisplayName,
|
|
1030
|
+
getPlatformName,
|
|
1031
|
+
parseBrowserFromUserAgent
|
|
878
1032
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/browser-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Browser SDK for Phantom Wallet with unified interface",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -24,15 +24,17 @@
|
|
|
24
24
|
"test": "jest",
|
|
25
25
|
"test:watch": "jest --watch",
|
|
26
26
|
"lint": "tsc --noEmit && eslint --cache . --ext .ts,.tsx",
|
|
27
|
+
"check-types": "tsc --noEmit",
|
|
27
28
|
"prettier": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
|
-
"@phantom/api-key-stamper": "^0.1.1",
|
|
31
31
|
"@phantom/base64url": "^0.1.0",
|
|
32
32
|
"@phantom/browser-injected-sdk": "^0.0.9",
|
|
33
|
-
"@phantom/client": "^0.1.
|
|
34
|
-
"@phantom/
|
|
35
|
-
"@phantom/
|
|
33
|
+
"@phantom/client": "^0.1.5",
|
|
34
|
+
"@phantom/constants": "^0.0.2",
|
|
35
|
+
"@phantom/embedded-provider-core": "^0.1.2",
|
|
36
|
+
"@phantom/indexed-db-stamper": "^0.1.1",
|
|
37
|
+
"@phantom/parsers": "^0.0.5",
|
|
36
38
|
"axios": "^1.10.0",
|
|
37
39
|
"bs58": "^6.0.0",
|
|
38
40
|
"buffer": "^6.0.3",
|