@phantom/browser-sdk 0.0.10 → 0.1.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 CHANGED
@@ -1,142 +1,296 @@
1
- # Phantom Browser SDK
1
+ # @phantom/browser-sdk
2
2
 
3
- The Phantom Browser SDK allows you to interact with the Phantom wallet from your web application. It uses a plugin system to support different blockchains.
3
+ Browser SDK for Phantom Wallet supporting both injected and embedded non-custodial wallets.
4
4
 
5
- ## Installation
6
-
7
- You can install the SDK using npm or yarn:
8
-
9
- **npm:**
5
+ ## Quick Start
10
6
 
11
7
  ```bash
12
8
  npm install @phantom/browser-sdk
13
9
  ```
14
10
 
15
- **yarn:**
11
+ ### Injected Provider (Browser Extension)
16
12
 
17
- ```bash
18
- yarn add @phantom/browser-sdk
13
+ ```typescript
14
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
15
+
16
+ // Connect to Phantom browser extension
17
+ const sdk = new BrowserSDK({
18
+ providerType: "injected",
19
+ });
20
+
21
+ const { addresses } = await sdk.connect();
22
+ console.log("Connected addresses:", addresses);
23
+
24
+ // Sign and send transactions
25
+ const result = await sdk.signAndSendTransaction({
26
+ networkId: NetworkId.SOLANA_MAINNET,
27
+ transaction: mySolanaTransaction,
28
+ });
29
+ ```
30
+
31
+ ### Embedded Provider
32
+
33
+ ```typescript
34
+ import { BrowserSDK, AddressType, NetworkId } from "@phantom/browser-sdk";
35
+
36
+ // Create embedded non-custodial wallet
37
+ const sdk = new BrowserSDK({
38
+ providerType: "embedded",
39
+ addressTypes: [AddressType.solana, AddressType.ethereum],
40
+ apiBaseUrl: "https://api.phantom.com",
41
+ organizationId: "your-org-id",
42
+ });
43
+
44
+ const { walletId, addresses } = await sdk.connect();
45
+ console.log("Wallet ID:", walletId);
46
+ console.log("Addresses:", addresses);
47
+
48
+ const result = await sdk.signAndSendTransaction({
49
+ networkId: NetworkId.SOLANA_MAINNET,
50
+ transaction: mySolanaTransaction,
51
+ });
52
+ ```
53
+
54
+ ## Features
55
+
56
+ - **🔒 Non-Custodial**: Full user control of private keys for both injected and embedded wallets
57
+ - **🌐 Dual Provider Support**: Works with Phantom browser extension or creates embedded wallets
58
+ - **🛠️ Native Transactions**: Work with blockchain-native objects, not base64url strings
59
+ - **🔗 Multi-Chain**: Solana, Ethereum, Bitcoin, Sui support
60
+ - **⚡ TypeScript**: Full type safety for all transaction formats
61
+ - **🎯 Unified API**: Same interface for both injected and embedded providers
62
+
63
+ ## Provider Types
64
+
65
+ ### Injected Provider
66
+
67
+ Uses the Phantom browser extension installed by the user. No additional configuration needed.
68
+
69
+ ```typescript
70
+ const sdk = new BrowserSDK({
71
+ providerType: "injected",
72
+ });
19
73
  ```
20
74
 
21
- ## Usage
75
+ ### Embedded Provider
76
+
77
+ Creates a non-custodial wallet embedded in your application. Requires API configuration.
78
+
79
+ ```typescript
80
+ const sdk = new BrowserSDK({
81
+ providerType: "embedded",
82
+ addressTypes: [AddressType.solana, AddressType.ethereum],
83
+ apiBaseUrl: "https://api.phantom.com",
84
+ organizationId: "your-org-id",
85
+ embeddedWalletType: "app-wallet", // or 'user-wallet'
86
+ });
87
+ ```
88
+
89
+ ### Embedded Wallet Types
90
+
91
+ #### App Wallet (`'app-wallet'`)
22
92
 
23
- Here's an example of how to import and use the SDK with the Solana plugin:
93
+ - **New wallets** created per application
94
+ - **Unfunded** by default - you need to fund them
95
+ - **Independent** from user's existing Phantom wallet
96
+ - **Perfect for**: Gaming, DeFi protocols, or apps that need fresh wallets
24
97
 
25
98
  ```typescript
26
- import { createPhantom } from "@phantom/browser-sdk";
27
- import { createSolanaPlugin } from "@phantom/browser-sdk/solana"; // Import the solana plugin
99
+ const sdk = new BrowserSDK({
100
+ providerType: "embedded",
101
+ embeddedWalletType: "app-wallet",
102
+ addressTypes: [AddressType.solana],
103
+ // ... other config
104
+ });
105
+ ```
106
+
107
+ #### User Wallet (`'user-wallet'`)
28
108
 
29
- // Create a Phantom instance with the Solana plugin
30
- const phantom = createPhantom({
31
- plugins: [createSolanaPlugin()],
109
+ - **Uses Phantom authentication** - user logs in with existing Phantom account
110
+ - **Potentially funded** - brings in user's existing wallet balance
111
+ - **Connected** to user's Phantom ecosystem
112
+ - **Perfect for**: Trading platforms, NFT marketplaces, or apps needing funded wallets
113
+
114
+ ```typescript
115
+ const sdk = new BrowserSDK({
116
+ providerType: "embedded",
117
+ embeddedWalletType: "user-wallet",
118
+ addressTypes: [AddressType.solana, AddressType.ethereum],
119
+ // ... other config
32
120
  });
121
+ ```
33
122
 
34
- // Now you can use the Solana-specific methods
35
- async function connectAndSign() {
36
- try {
37
- // Attempt to connect to the wallet
38
- const connectionResult = await phantom.solana.connect();
39
- console.log("Connection Result:", connectionResult.address);
40
-
41
- // Example: Sign in (if supported by the specific provider/plugin)
42
- // Construct SolanaSignInData according to your needs
43
- const signInData = { domain: window.location.host, statement: "Please sign in to access this dApp." };
44
- const signInResult = await phantom.solana.signIn(signInData);
45
- console.log("Sign In Result:", signInResult.address);
46
-
47
- // Example: Sign a message
48
- const message = new TextEncoder().encode("Hello from Phantom Browser SDK!");
49
- const signedMessage = await phantom.solana.signMessage(message, "utf8");
50
- console.log("Signed Message:", signedMessage);
51
- } catch (error) {
52
- console.error("Error interacting with Phantom:", error);
53
- }
123
+ ### Available AddressTypes (Embedded Only)
124
+
125
+ | AddressType | Networks Supported |
126
+ | --------------------------- | ------------------------------------------- |
127
+ | `AddressType.solana` | Solana Mainnet, Devnet, Testnet |
128
+ | `AddressType.ethereum` | Ethereum, Polygon, Arbitrum, Optimism, Base |
129
+ | `AddressType.bitcoinSegwit` | Bitcoin Mainnet, Testnet |
130
+ | `AddressType.sui` | Sui Mainnet, Testnet, Devnet |
131
+
132
+ ### Solana Provider Configuration
133
+
134
+ When using `AddressType.solana`, you can choose between two Solana libraries:
135
+
136
+ ```typescript
137
+ const sdk = new BrowserSDK({
138
+ providerType: "embedded",
139
+ addressTypes: [AddressType.solana],
140
+ solanaProvider: "web3js", // or 'kit'
141
+ // ... other config
142
+ });
143
+ ```
144
+
145
+ **Provider Options:**
146
+
147
+ - `'web3js'` (default) - Uses `@solana/web3.js` library
148
+ - `'kit'` - Uses `@solana/kit` library (modern, TypeScript-first)
149
+
150
+ **When to use each:**
151
+
152
+ - **@solana/web3.js**: Better ecosystem compatibility, wider community support
153
+ - **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
154
+
155
+ ## API Reference
156
+
157
+ ### Constructor
158
+
159
+ ```typescript
160
+ new BrowserSDK(config: BrowserSDKConfig)
161
+ ```
162
+
163
+ #### BrowserSDKConfig
164
+
165
+ ```typescript
166
+ interface BrowserSDKConfig {
167
+ providerType: "injected" | "embedded";
168
+
169
+ // Required for embedded provider only
170
+ addressTypes?: AddressType[]; // Networks to enable
171
+ apiBaseUrl?: string; // Phantom API base URL
172
+ organizationId?: string; // Your organization ID
173
+ authUrl?: string; // Custom auth URL (optional)
174
+ embeddedWalletType?: "app-wallet" | "user-wallet"; // Wallet type
175
+ solanaProvider?: "web3js" | "kit"; // Solana library choice (default: 'web3js')
54
176
  }
177
+ ```
178
+
179
+ ### Methods
180
+
181
+ #### connect()
55
182
 
56
- connectAndSign();
183
+ Connect to wallet and get addresses for configured AddressTypes.
184
+
185
+ ```typescript
186
+ const result = await sdk.connect();
187
+ // Returns: { walletId: string, addresses: WalletAddress[] }
188
+ // addresses only includes types from addressTypes config
57
189
  ```
58
190
 
59
- ### Available Solana Methods
191
+ #### signAndSendTransaction(transaction)
60
192
 
61
- Once the `phantom.solana` object is initialized, you can access the following methods:
193
+ Sign and send a native transaction object.
62
194
 
63
- - `connect(opts?: { onlyIfTrusted?: boolean }): Promise<string>`
64
- - Connects to the Phantom wallet. Optionally, `onlyIfTrusted` can be set to true to only connect if the dApp is already trusted.
65
- - `disconnect(): Promise<void>`
66
- - Disconnects from the Phantom wallet.
67
- - `getAccount(): Promise<string | undefined>`
68
- - Gets the current connected address
69
- - `signIn(): Promise<SignInResult>`
70
- - Initiates a sign-in request to the wallet.
71
- - `signMessage(message: Uint8Array | string, display?: 'utf8' | 'hex'): Promise<SignedMessage>`
72
- - Prompts the user to sign a given message.
73
- - `signAndSendTransaction(transaction: Transaction): Promise<{ signature: string; address?: string }>`
74
- - Prompts the user to sign **and send** a Kit `Transaction` and returns the confirmed signature.
195
+ ```typescript
196
+ // Solana transaction
197
+ const result = await sdk.signAndSendTransaction({
198
+ networkId: NetworkId.SOLANA_MAINNET,
199
+ transaction: solanaTransaction, // Native Transaction or VersionedTransaction
200
+ });
75
201
 
76
- ### Available Extension Methods
202
+ // Ethereum transaction
203
+ const result = await sdk.signAndSendTransaction({
204
+ networkId: NetworkId.ETHEREUM_MAINNET,
205
+ transaction: {
206
+ to: "0x...",
207
+ value: parseEther("1"), // 1 ETH
208
+ gas: 21000n,
209
+ },
210
+ });
211
+ ```
77
212
 
78
- Once the `phantom.extension` object is initialized, you can access the following methods:
213
+ #### signMessage(message, networkId)
79
214
 
80
- - `isInstalled(): boolean`
81
- - Displays `true` if the phantom extension is installed, `false` if not
215
+ Sign a message string.
82
216
 
83
- ### Event Handling
217
+ ```typescript
218
+ const signature = await sdk.signMessage("Hello from Phantom!", NetworkId.SOLANA_MAINNET);
219
+ ```
84
220
 
85
- The SDK also allows you to listen for `connect`, `disconnect`, and `accountChanged` events:
221
+ #### getAddresses()
86
222
 
87
- - `addEventListener(event: PhantomEventType, callback: PhantomEventCallback): () => void`
223
+ Get connected wallet addresses.
88
224
 
89
- - Registers a callback that will be invoked when the specified event occurs.
90
- - For the `connect` event, the callback receives the public key (as a string) of the connected account.
91
- - For the `disconnect` event, the callback receives no arguments.
92
- - For the `accountChanged` event, the callback receives the new public key (as a string).
93
- - Returns a function that, when called, will unregister the callback.
94
- - Multiple callbacks can be registered for the same event.
225
+ ```typescript
226
+ const addresses = await sdk.getAddresses();
227
+ // Returns addresses matching configured AddressTypes
228
+ ```
229
+
230
+ #### disconnect()
95
231
 
96
- **Example:**
232
+ Disconnect from wallet and clear session.
233
+
234
+ ```typescript
235
+ await sdk.disconnect();
236
+ ```
97
237
 
98
- ```typescript
99
- const phantom = createPhantom({ plugins: [createSolanaPlugin()] });
238
+ ## Transaction Examples
100
239
 
101
- const handleConnect = (address: string) => {
102
- console.log(`Wallet connected with public key: ${address}`);
103
- };
240
+ ### Solana Transactions
104
241
 
105
- const clearConnectListener = phantom.solana.addEventListener("connect", handleConnect);
242
+ The SDK supports two different Solana transaction libraries. Choose based on your needs:
106
243
 
107
- const handleAccountChanged = (newAddress: string) => {
108
- console.log(`Account changed to: ${newAddress}`);
109
- };
244
+ #### Option 1: @solana/web3.js (Legacy Library)
110
245
 
111
- const clearAccountChangedListener = phantom.solana.addEventListener("accountChanged", handleAccountChanged);
246
+ Traditional Solana library with broader ecosystem support.
112
247
 
113
- // To stop listening for a specific event:
114
- // clearConnectListener();
115
- // clearAccountChangedListener();
116
- ```
248
+ ```bash
249
+ npm install @solana/web3.js
250
+ ```
117
251
 
118
- - `removeEventListener(event: PhantomEventType, callback: PhantomEventCallback): void`
252
+ ```typescript
253
+ import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
254
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
255
+
256
+ // Create native Solana transaction
257
+ const transaction = new Transaction().add(
258
+ SystemProgram.transfer({
259
+ fromPubkey: new PublicKey(fromAddress),
260
+ toPubkey: new PublicKey(toAddress),
261
+ lamports: 0.001 * LAMPORTS_PER_SOL,
262
+ }),
263
+ );
119
264
 
120
- - Unregisters a previously registered callback for the specified event.
265
+ // Send native transaction object - no encoding needed!
266
+ const result = await sdk.signAndSendTransaction({
267
+ networkId: NetworkId.SOLANA_MAINNET,
268
+ transaction: transaction,
269
+ });
121
270
 
122
- **Example:**
271
+ console.log("Transaction signature:", result.rawTransaction);
272
+ ```
123
273
 
124
- ```typescript
125
- const phantom = createPhantom({ plugins: [createSolanaPlugin()] });
274
+ **VersionedTransaction with @solana/web3.js:**
126
275
 
127
- const handleDisconnect = () => {
128
- console.log("Wallet disconnected");
129
- };
276
+ ```typescript
277
+ import { VersionedTransaction } from "@solana/web3.js";
130
278
 
131
- phantom.solana.addEventListener("disconnect", handleDisconnect);
279
+ const versionedTx = new VersionedTransaction(message);
132
280
 
133
- // To stop listening for this specific disconnect event:
134
- // phantom.solana.removeEventListener("disconnect", handleDisconnect);
135
- ```
281
+ const result = await sdk.signAndSendTransaction({
282
+ networkId: NetworkId.SOLANA_DEVNET,
283
+ transaction: versionedTx,
284
+ });
285
+ ```
136
286
 
137
- ### Creating a transaction
287
+ #### Option 2: @solana/kit (Modern Library)
138
288
 
139
- Phantom's SDK uses the `@solana/kit` library to create transactions. You can use the `createTransactionMessage` function to create a transaction message.
289
+ New high-performance Solana library with better TypeScript support.
290
+
291
+ ```bash
292
+ npm install @solana/kit
293
+ ```
140
294
 
141
295
  ```typescript
142
296
  import {
@@ -148,20 +302,406 @@ import {
148
302
  address,
149
303
  compileTransaction,
150
304
  } from "@solana/kit";
305
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
151
306
 
152
- // Example: Sign and send a transaction
153
-
154
- const rpc = createSolanaRpc("https://my-rpc-url.com"); // Replace with your own RPC URL
155
-
307
+ // Create transaction with @solana/kit
308
+ const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
156
309
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
157
310
 
158
311
  const transactionMessage = pipe(
159
312
  createTransactionMessage({ version: 0 }),
160
- tx => setTransactionMessageFeePayer(address(userPublicKey as string), tx),
313
+ tx => setTransactionMessageFeePayer(address(userPublicKey), tx),
161
314
  tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
162
315
  );
163
316
 
164
317
  const transaction = compileTransaction(transactionMessage);
165
318
 
166
- const { signature } = await phantomInstance.solana.signAndSendTransaction(transaction);
319
+ const result = await sdk.signAndSendTransaction({
320
+ networkId: NetworkId.SOLANA_MAINNET,
321
+ transaction: transaction,
322
+ });
323
+ ```
324
+
325
+ ### Ethereum Transactions (with Viem)
326
+
327
+ ```typescript
328
+ import { parseEther, parseGwei, encodeFunctionData } from "viem";
329
+ import { BrowserSDK, NetworkId } from "@phantom/browser-sdk";
330
+
331
+ // Simple ETH transfer
332
+ const result = await sdk.signAndSendTransaction({
333
+ networkId: NetworkId.ETHEREUM_MAINNET,
334
+ transaction: {
335
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
336
+ value: parseEther("1"), // 1 ETH
337
+ gas: 21000n,
338
+ gasPrice: parseGwei("20"), // 20 gwei
339
+ },
340
+ });
341
+
342
+ // EIP-1559 transaction with maxFeePerGas
343
+ const result = await sdk.signAndSendTransaction({
344
+ networkId: NetworkId.ETHEREUM_MAINNET,
345
+ transaction: {
346
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
347
+ value: parseEther("1"),
348
+ data: encodeFunctionData({
349
+ abi: tokenAbi,
350
+ functionName: "transfer",
351
+ args: ["0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E", parseEther("1")],
352
+ }),
353
+ gas: 50000n,
354
+ maxFeePerGas: parseGwei("30"), // 30 gwei
355
+ maxPriorityFeePerGas: parseGwei("2"), // 2 gwei
356
+ type: "eip1559",
357
+ },
358
+ });
359
+ ```
360
+
361
+ #### Other EVM Networks
362
+
363
+ ```typescript
364
+ // Polygon transaction
365
+ const result = await sdk.signAndSendTransaction({
366
+ networkId: NetworkId.POLYGON_MAINNET,
367
+ transaction: {
368
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
369
+ value: parseEther("1"), // 1 MATIC
370
+ gas: 21000n,
371
+ },
372
+ });
373
+
374
+ // Arbitrum transaction
375
+ const result = await sdk.signAndSendTransaction({
376
+ networkId: NetworkId.ARBITRUM_ONE,
377
+ transaction: {
378
+ to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
379
+ value: parseEther("0.1"), // 0.1 ETH
380
+ gas: 21000n,
381
+ },
382
+ });
383
+ ```
384
+
385
+ ### Bitcoin Transactions
386
+
387
+ ```typescript
388
+ // Bitcoin transaction
389
+ const result = await sdk.signAndSendTransaction({
390
+ networkId: NetworkId.BITCOIN_MAINNET,
391
+ transaction: {
392
+ inputs: [
393
+ {
394
+ txid: "previous-transaction-id",
395
+ vout: 0,
396
+ scriptSig: "...",
397
+ },
398
+ ],
399
+ outputs: [
400
+ {
401
+ value: 50000, // satoshis
402
+ scriptPubKey: "76a914...88ac", // P2PKH script
403
+ },
404
+ ],
405
+ version: 2,
406
+ locktime: 0,
407
+ },
408
+ });
409
+
410
+ // Bitcoin testnet
411
+ const result = await sdk.signAndSendTransaction({
412
+ networkId: NetworkId.BITCOIN_TESTNET,
413
+ transaction: {
414
+ // ... transaction details
415
+ },
416
+ });
417
+ ```
418
+
419
+ ### Sui Transactions
420
+
421
+ ```typescript
422
+ import { TransactionBlock } from "@mysten/sui.js/transactions";
423
+
424
+ // Create Sui transaction block
425
+ const txb = new TransactionBlock();
426
+ txb.transferObjects([coin], recipientAddress);
427
+
428
+ const result = await sdk.signAndSendTransaction({
429
+ networkId: NetworkId.SUI_MAINNET,
430
+ transaction: {
431
+ kind: "moveCall", // or 'transferObject', 'transferSui', 'pay'
432
+ data: txb, // TransactionBlock from @mysten/sui.js
433
+ },
434
+ });
435
+
436
+ // Sui testnet
437
+ const result = await sdk.signAndSendTransaction({
438
+ networkId: NetworkId.SUI_TESTNET,
439
+ transaction: {
440
+ kind: "transferSui",
441
+ data: suiTransactionData,
442
+ },
443
+ });
444
+ ```
445
+
446
+ ## Network IDs Reference
447
+
448
+ Use the exported `NetworkId` enum for type safety:
449
+
450
+ ```typescript
451
+ import { NetworkId } from "@phantom/browser-sdk";
452
+ ```
453
+
454
+ ### Solana
455
+
456
+ - `NetworkId.SOLANA_MAINNET` - Solana Mainnet Beta
457
+ - `NetworkId.SOLANA_DEVNET` - Solana Devnet
458
+ - `NetworkId.SOLANA_TESTNET` - Solana Testnet
459
+
460
+ ### Ethereum/EVM
461
+
462
+ - `NetworkId.ETHEREUM_MAINNET` - Ethereum Mainnet
463
+ - `NetworkId.ETHEREUM_SEPOLIA` - Ethereum Sepolia Testnet
464
+ - `NetworkId.POLYGON_MAINNET` - Polygon Mainnet
465
+ - `NetworkId.ARBITRUM_ONE` - Arbitrum One
466
+ - `NetworkId.OPTIMISM_MAINNET` - Optimism Mainnet
467
+ - `NetworkId.BASE_MAINNET` - Base Mainnet
468
+
469
+ ### Bitcoin
470
+
471
+ - `NetworkId.BITCOIN_MAINNET` - Bitcoin Mainnet
472
+ - `NetworkId.BITCOIN_TESTNET` - Bitcoin Testnet
473
+
474
+ ### Sui
475
+
476
+ - `NetworkId.SUI_MAINNET` - Sui Mainnet
477
+ - `NetworkId.SUI_TESTNET` - Sui Testnet
478
+ - `NetworkId.SUI_DEVNET` - Sui Devnet
479
+
480
+ ## Advanced Usage
481
+
482
+ ### Multi-Chain Application
483
+
484
+ ```typescript
485
+ import { BrowserSDK, AddressType } from "@phantom/browser-sdk";
486
+
487
+ const sdk = new BrowserSDK({
488
+ addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui],
489
+ apiBaseUrl: "https://api.phantom.com",
490
+ organizationId: "your-org-id",
491
+ });
492
+
493
+ class MultiChainWallet {
494
+ async sendSolana(amount: number, recipient: string) {
495
+ const transaction = new Transaction().add(
496
+ SystemProgram.transfer({
497
+ fromPubkey: new PublicKey(this.solanaAddress),
498
+ toPubkey: new PublicKey(recipient),
499
+ lamports: amount * LAMPORTS_PER_SOL,
500
+ }),
501
+ );
502
+
503
+ return await sdk.signAndSendTransaction({
504
+ networkId: NetworkId.SOLANA_MAINNET,
505
+ transaction,
506
+ });
507
+ }
508
+
509
+ async sendEthereum(amount: string, recipient: string) {
510
+ return await sdk.signAndSendTransaction({
511
+ networkId: NetworkId.ETHEREUM_MAINNET,
512
+ transaction: {
513
+ to: recipient,
514
+ value: parseEther(amount),
515
+ gas: 21000n,
516
+ },
517
+ });
518
+ }
519
+
520
+ async sendSui(coinId: string, recipient: string) {
521
+ const txb = new TransactionBlock();
522
+ txb.transferObjects([coinId], recipient);
523
+
524
+ return await sdk.signAndSendTransaction({
525
+ networkId: NetworkId.SUI_MAINNET,
526
+ transaction: {
527
+ kind: "transferObject",
528
+ data: txb,
529
+ },
530
+ });
531
+ }
532
+ }
533
+ ```
534
+
535
+ ### Error Handling
536
+
537
+ ```typescript
538
+ try {
539
+ const result = await sdk.signAndSendTransaction({
540
+ networkId: NetworkId.SOLANA_MAINNET,
541
+ transaction: myTransaction,
542
+ });
543
+ console.log("Success:", result);
544
+ } catch (error) {
545
+ if (error.message.includes("User rejected")) {
546
+ console.log("User cancelled the transaction");
547
+ } else if (error.message.includes("insufficient funds")) {
548
+ console.log("Not enough balance");
549
+ } else {
550
+ console.error("Transaction failed:", error);
551
+ }
552
+ }
553
+ ```
554
+
555
+ ### Bundle Optimization Tips
556
+
557
+ 1. **Only include networks you need**:
558
+
559
+ ```typescript
560
+ // Good: Only Solana (~250KB)
561
+ addressTypes: [AddressType.solana];
562
+
563
+ // Avoid: All networks if not needed (~800KB+)
564
+ addressTypes: [AddressType.solana, AddressType.ethereum, AddressType.sui, AddressType.bitcoinSegwit];
565
+ ```
566
+
567
+ 2. **Install dependencies based on enabled networks**:
568
+
569
+ | AddressType | Required Dependencies | Bundle Size |
570
+ | --------------------------- | ---------------------------------- | ----------- |
571
+ | `AddressType.solana` | `@solana/web3.js` OR `@solana/kit` | ~250KB |
572
+ | `AddressType.ethereum` | `viem` | ~300KB |
573
+ | `AddressType.bitcoinSegwit` | `bitcoinjs-lib` | ~200KB |
574
+ | `AddressType.sui` | `@mysten/sui.js` | ~250KB |
575
+
576
+ **Example package.json for Solana + Ethereum (using @solana/web3.js)**:
577
+
578
+ ```json
579
+ {
580
+ "dependencies": {
581
+ "@phantom/browser-sdk": "^1.0.0",
582
+ "@solana/web3.js": "^1.87.0",
583
+ "viem": "^2.0.0"
584
+ }
585
+ }
586
+ ```
587
+
588
+ **Example package.json for Solana + Ethereum (using @solana/kit)**:
589
+
590
+ ```json
591
+ {
592
+ "dependencies": {
593
+ "@phantom/browser-sdk": "^1.0.0",
594
+ "@solana/kit": "^2.0.0",
595
+ "viem": "^2.0.0"
596
+ }
597
+ }
598
+ ```
599
+
600
+ **Example package.json for Solana only (using @solana/web3.js)**:
601
+
602
+ ```json
603
+ {
604
+ "dependencies": {
605
+ "@phantom/browser-sdk": "^1.0.0",
606
+ "@solana/web3.js": "^1.87.0"
607
+ }
608
+ }
609
+ ```
610
+
611
+ **Example package.json for Solana only (using @solana/kit)**:
612
+
613
+ ```json
614
+ {
615
+ "dependencies": {
616
+ "@phantom/browser-sdk": "^1.0.0",
617
+ "@solana/kit": "^2.0.0"
618
+ }
619
+ }
620
+ ```
621
+
622
+ **Example package.json for all networks (using @solana/web3.js)**:
623
+
624
+ ```json
625
+ {
626
+ "dependencies": {
627
+ "@phantom/browser-sdk": "^1.0.0",
628
+ "@solana/web3.js": "^1.87.0",
629
+ "viem": "^2.0.0",
630
+ "bitcoinjs-lib": "^6.1.0",
631
+ "@mysten/sui.js": "^0.50.0"
632
+ }
633
+ }
634
+ ```
635
+
636
+ **Example package.json for all networks (using @solana/kit)**:
637
+
638
+ ```json
639
+ {
640
+ "dependencies": {
641
+ "@phantom/browser-sdk": "^1.0.0",
642
+ "@solana/kit": "^2.0.0",
643
+ "viem": "^2.0.0",
644
+ "bitcoinjs-lib": "^6.1.0",
645
+ "@mysten/sui.js": "^0.50.0"
646
+ }
647
+ }
648
+ ```
649
+
650
+ 3. **Monitor bundle size**:
651
+ ```bash
652
+ # Analyze your bundle
653
+ npx webpack-bundle-analyzer dist/main.js
654
+ ```
655
+
656
+ ## Server Setup for Embedded Wallets
657
+
658
+ For embedded wallets, you need to set up a backend endpoint. Add the `serverUrl` parameter to your SDK configuration:
659
+
660
+ ```typescript
661
+ const sdk = new BrowserSDK({
662
+ providerType: "embedded",
663
+ addressTypes: [AddressType.solana],
664
+ apiBaseUrl: "https://api.phantom.com",
665
+ organizationId: "your-org-id",
666
+ serverUrl: "http://localhost:3000/api",
667
+ });
668
+ ```
669
+
670
+ ### Required Backend Endpoint
671
+
672
+ Your backend needs an endpoint that uses the server-sdk:
673
+
674
+ ```javascript
675
+ // server.js
676
+ const express = require("express");
677
+ const { ServerSDK } = require("@phantom/server-sdk");
678
+
679
+ const app = express();
680
+ app.use(express.json());
681
+
682
+ const serverSDK = new ServerSDK({
683
+ organizationId: process.env.ORGANIZATION_ID,
684
+ apiPrivateKey: process.env.PRIVATE_KEY,
685
+ apiBaseUrl: process.env.API_URL,
686
+ });
687
+
688
+ app.post("/api/organizations", async (req, res) => {
689
+ try {
690
+ const { userId } = req.body;
691
+
692
+ if (!userId) {
693
+ return res.status(400).json({ error: "userId is required" });
694
+ }
695
+
696
+ const organization = await serverSDK.getOrCreateChildOrganizationByTag({
697
+ tag: userId,
698
+ });
699
+
700
+ res.json({ organizationId: organization.id });
701
+ } catch (error) {
702
+ res.status(500).json({ error: "Failed to process request" });
703
+ }
704
+ });
705
+
706
+ app.listen(3000);
167
707
  ```