@phantom/react-sdk 1.0.0-beta.2 → 1.0.0-beta.21
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 +107 -95
- package/dist/index.d.ts +22 -43
- package/dist/index.js +98 -208
- package/dist/index.mjs +99 -209
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -52,11 +52,11 @@ function App() {
|
|
|
52
52
|
|
|
53
53
|
function WalletComponent() {
|
|
54
54
|
const { connect, isConnecting } = useConnect();
|
|
55
|
-
const solana = useSolana();
|
|
56
|
-
const ethereum = useEthereum();
|
|
55
|
+
const { solana } = useSolana();
|
|
56
|
+
const { ethereum } = useEthereum();
|
|
57
57
|
|
|
58
58
|
const handleConnect = async () => {
|
|
59
|
-
const { addresses } = await connect();
|
|
59
|
+
const { addresses } = await connect({ provider: "injected" });
|
|
60
60
|
console.log("Connected addresses:", addresses);
|
|
61
61
|
};
|
|
62
62
|
|
|
@@ -94,9 +94,8 @@ function App() {
|
|
|
94
94
|
<PhantomProvider
|
|
95
95
|
config={{
|
|
96
96
|
providerType: "embedded",
|
|
97
|
-
|
|
97
|
+
appId: "your-app-id", // Get your app ID from phantom.com/portal
|
|
98
98
|
addressTypes: [AddressType.solana, AddressType.ethereum],
|
|
99
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
100
99
|
}}
|
|
101
100
|
>
|
|
102
101
|
<YourApp />
|
|
@@ -116,12 +115,12 @@ The React SDK follows a clear connection pattern:
|
|
|
116
115
|
```tsx
|
|
117
116
|
function WalletExample() {
|
|
118
117
|
const { connect } = useConnect();
|
|
119
|
-
const solana = useSolana();
|
|
120
|
-
const ethereum = useEthereum();
|
|
118
|
+
const { solana } = useSolana();
|
|
119
|
+
const { ethereum } = useEthereum();
|
|
121
120
|
|
|
122
|
-
// 1. Connect first
|
|
121
|
+
// 1. Connect first (provider parameter is required)
|
|
123
122
|
const handleConnect = async () => {
|
|
124
|
-
await connect();
|
|
123
|
+
await connect({ provider: "injected" });
|
|
125
124
|
};
|
|
126
125
|
|
|
127
126
|
// 2. Then use chain-specific operations
|
|
@@ -137,26 +136,40 @@ function WalletExample() {
|
|
|
137
136
|
|
|
138
137
|
### Connection Options
|
|
139
138
|
|
|
140
|
-
|
|
139
|
+
The `connect()` method requires a `provider` parameter and automatically switches between providers based on the authentication method you specify:
|
|
141
140
|
|
|
142
141
|
```tsx
|
|
143
142
|
const { connect } = useConnect();
|
|
144
143
|
|
|
145
|
-
//
|
|
146
|
-
|
|
144
|
+
// Connect with injected provider (Phantom extension)
|
|
145
|
+
// Automatically switches to injected provider if not already using it
|
|
146
|
+
await connect({
|
|
147
|
+
provider: "injected",
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Connect with Google authentication (embedded provider)
|
|
151
|
+
// Automatically switches to embedded provider if not already using it
|
|
152
|
+
await connect({
|
|
153
|
+
provider: "google",
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Connect with Apple authentication (embedded provider)
|
|
157
|
+
// Automatically switches to embedded provider if not already using it
|
|
158
|
+
await connect({
|
|
159
|
+
provider: "apple",
|
|
160
|
+
});
|
|
147
161
|
|
|
148
|
-
//
|
|
162
|
+
// Connect with Phantom authentication (embedded provider)
|
|
163
|
+
// Uses Phantom extension or mobile app for authentication
|
|
164
|
+
// Automatically switches to embedded provider if not already using it
|
|
149
165
|
await connect({
|
|
150
|
-
|
|
151
|
-
provider: "google",
|
|
152
|
-
},
|
|
166
|
+
provider: "phantom",
|
|
153
167
|
});
|
|
154
168
|
|
|
155
|
-
//
|
|
169
|
+
// Connect with JWT authentication (embedded provider)
|
|
156
170
|
await connect({
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
},
|
|
171
|
+
provider: "jwt",
|
|
172
|
+
jwtToken: "your-jwt-token",
|
|
160
173
|
});
|
|
161
174
|
```
|
|
162
175
|
|
|
@@ -181,26 +194,7 @@ Uses the Phantom browser extension installed by the user.
|
|
|
181
194
|
|
|
182
195
|
Creates non-custodial wallets embedded in your application.
|
|
183
196
|
|
|
184
|
-
####
|
|
185
|
-
|
|
186
|
-
- **New wallets** created per application
|
|
187
|
-
- **Unfunded** by default - you need to fund them
|
|
188
|
-
- **Independent** from user's existing Phantom wallet
|
|
189
|
-
|
|
190
|
-
```tsx
|
|
191
|
-
<PhantomProvider
|
|
192
|
-
config={{
|
|
193
|
-
providerType: "embedded",
|
|
194
|
-
embeddedWalletType: "app-wallet",
|
|
195
|
-
addressTypes: [AddressType.solana],
|
|
196
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
197
|
-
}}
|
|
198
|
-
>
|
|
199
|
-
<YourApp />
|
|
200
|
-
</PhantomProvider>
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
#### User Wallet (For existing Phantom users)
|
|
197
|
+
#### User Wallet
|
|
204
198
|
|
|
205
199
|
- **Uses Phantom authentication** - user logs in with existing account
|
|
206
200
|
- **Potentially funded** - brings existing wallet balance
|
|
@@ -210,41 +204,14 @@ Creates non-custodial wallets embedded in your application.
|
|
|
210
204
|
<PhantomProvider
|
|
211
205
|
config={{
|
|
212
206
|
providerType: "embedded",
|
|
213
|
-
|
|
207
|
+
appId: "your-app-id",
|
|
214
208
|
addressTypes: [AddressType.solana, AddressType.ethereum],
|
|
215
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
216
|
-
}}
|
|
217
|
-
>
|
|
218
|
-
<YourApp />
|
|
219
|
-
</PhantomProvider>
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
## Solana Provider Configuration
|
|
223
|
-
|
|
224
|
-
When using `AddressType.solana`, you can choose between two Solana libraries:
|
|
225
|
-
|
|
226
|
-
```tsx
|
|
227
|
-
<PhantomProvider
|
|
228
|
-
config={{
|
|
229
|
-
providerType: "embedded",
|
|
230
|
-
addressTypes: [AddressType.solana],
|
|
231
|
-
solanaProvider: "web3js", // or 'kit'
|
|
232
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
233
209
|
}}
|
|
234
210
|
>
|
|
235
211
|
<YourApp />
|
|
236
212
|
</PhantomProvider>
|
|
237
213
|
```
|
|
238
214
|
|
|
239
|
-
**Provider Options:**
|
|
240
|
-
|
|
241
|
-
- `'web3js'` (default) - Uses `@solana/web3.js` library
|
|
242
|
-
- `'kit'` - Uses `@solana/kit` library (modern, TypeScript-first)
|
|
243
|
-
|
|
244
|
-
**When to use each:**
|
|
245
|
-
|
|
246
|
-
- **@solana/web3.js**: Better ecosystem compatibility, wider community support
|
|
247
|
-
- **@solana/kit**: Better TypeScript support, modern architecture, smaller bundle size
|
|
248
215
|
|
|
249
216
|
## Available Hooks
|
|
250
217
|
|
|
@@ -262,7 +229,7 @@ function ConnectButton() {
|
|
|
262
229
|
|
|
263
230
|
const handleConnect = async () => {
|
|
264
231
|
try {
|
|
265
|
-
const {
|
|
232
|
+
const { addresses } = await connect({ provider: "injected" });
|
|
266
233
|
console.log("Connected addresses:", addresses);
|
|
267
234
|
} catch (err) {
|
|
268
235
|
console.error("Failed to connect:", err);
|
|
@@ -352,6 +319,33 @@ function ExtensionStatus() {
|
|
|
352
319
|
}
|
|
353
320
|
```
|
|
354
321
|
|
|
322
|
+
#### useIsPhantomLoginAvailable
|
|
323
|
+
|
|
324
|
+
Check if Phantom Login is available (requires extension installed and `phantom_login` feature support):
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import { useIsPhantomLoginAvailable } from "@phantom/react-sdk";
|
|
328
|
+
|
|
329
|
+
function PhantomLoginButton() {
|
|
330
|
+
const { isLoading, isAvailable } = useIsPhantomLoginAvailable();
|
|
331
|
+
const { connect } = useConnect();
|
|
332
|
+
|
|
333
|
+
if (isLoading) {
|
|
334
|
+
return <div>Checking Phantom Login availability...</div>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (!isAvailable) {
|
|
338
|
+
return null; // Don't show button if Phantom Login is not available
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return (
|
|
342
|
+
<button onClick={() => connect({ provider: "phantom" })}>
|
|
343
|
+
Login with Phantom
|
|
344
|
+
</button>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
355
349
|
### Chain-Specific Hooks
|
|
356
350
|
|
|
357
351
|
#### useSolana
|
|
@@ -363,7 +357,7 @@ import { useSolana } from "@phantom/react-sdk";
|
|
|
363
357
|
import { VersionedTransaction, TransactionMessage, SystemProgram, PublicKey, Connection } from "@solana/web3.js";
|
|
364
358
|
|
|
365
359
|
function SolanaOperations() {
|
|
366
|
-
const solana = useSolana();
|
|
360
|
+
const { solana } = useSolana();
|
|
367
361
|
|
|
368
362
|
const signMessage = async () => {
|
|
369
363
|
const signature = await solana.signMessage("Hello Solana!");
|
|
@@ -392,7 +386,7 @@ function SolanaOperations() {
|
|
|
392
386
|
|
|
393
387
|
// Sign and send
|
|
394
388
|
const result = await solana.signAndSendTransaction(transaction);
|
|
395
|
-
console.log("Transaction sent:", result.
|
|
389
|
+
console.log("Transaction sent:", result.signature);
|
|
396
390
|
};
|
|
397
391
|
|
|
398
392
|
const switchNetwork = async () => {
|
|
@@ -428,7 +422,7 @@ Hook for Ethereum chain operations:
|
|
|
428
422
|
import { useEthereum } from "@phantom/react-sdk";
|
|
429
423
|
|
|
430
424
|
function EthereumOperations() {
|
|
431
|
-
const ethereum = useEthereum();
|
|
425
|
+
const { ethereum } = useEthereum();
|
|
432
426
|
|
|
433
427
|
const signPersonalMessage = async () => {
|
|
434
428
|
const accounts = await ethereum.getAccounts();
|
|
@@ -513,12 +507,27 @@ function EthereumOperations() {
|
|
|
513
507
|
- `signTypedData(typedData)` - Sign EIP-712 typed data
|
|
514
508
|
- `signTransaction(transaction)` - Sign transaction without sending
|
|
515
509
|
- `sendTransaction(transaction)` - Sign and send transaction
|
|
516
|
-
- `switchChain(chainId)` - Switch chains
|
|
510
|
+
- `switchChain(chainId)` - Switch chains (accepts chain ID as number or a hex string)
|
|
517
511
|
- `getChainId()` - Get current chain ID
|
|
518
512
|
- `getAccounts()` - Get connected accounts
|
|
519
513
|
- `isConnected` - Connection status
|
|
520
514
|
- `isAvailable` - Provider availability
|
|
521
515
|
|
|
516
|
+
**Supported EVM Networks:**
|
|
517
|
+
|
|
518
|
+
| Network | Chain ID | Usage |
|
|
519
|
+
|---------|----------|-------|
|
|
520
|
+
| Ethereum Mainnet | `1` | `ethereum.switchChain(1)` |
|
|
521
|
+
| Ethereum Sepolia | `11155111` | `ethereum.switchChain(11155111)` |
|
|
522
|
+
| Polygon Mainnet | `137` | `ethereum.switchChain(137)` |
|
|
523
|
+
| Polygon Amoy | `80002` | `ethereum.switchChain(80002)` |
|
|
524
|
+
| Base Mainnet | `8453` | `ethereum.switchChain(8453)` |
|
|
525
|
+
| Base Sepolia | `84532` | `ethereum.switchChain(84532)` |
|
|
526
|
+
| Arbitrum One | `42161` | `ethereum.switchChain(42161)` |
|
|
527
|
+
| Arbitrum Sepolia | `421614` | `ethereum.switchChain(421614)` |
|
|
528
|
+
| Monad Mainnet | `143` | `ethereum.switchChain(143)` |
|
|
529
|
+
| Monad Testnet | `10143` | `ethereum.switchChain(10143)` |
|
|
530
|
+
|
|
522
531
|
### Auto-Confirm Hook (Injected Provider Only)
|
|
523
532
|
|
|
524
533
|
#### useAutoConfirm
|
|
@@ -661,7 +670,7 @@ import { VersionedTransaction, TransactionMessage, SystemProgram, PublicKey, Con
|
|
|
661
670
|
import { useSolana } from "@phantom/react-sdk";
|
|
662
671
|
|
|
663
672
|
function SolanaExample() {
|
|
664
|
-
const solana = useSolana();
|
|
673
|
+
const { solana } = useSolana();
|
|
665
674
|
|
|
666
675
|
const sendTransaction = async () => {
|
|
667
676
|
// Get recent blockhash
|
|
@@ -687,7 +696,7 @@ function SolanaExample() {
|
|
|
687
696
|
|
|
688
697
|
// Sign and send using chain-specific hook
|
|
689
698
|
const result = await solana.signAndSendTransaction(transaction);
|
|
690
|
-
console.log("Transaction sent:", result.
|
|
699
|
+
console.log("Transaction sent:", result.signature);
|
|
691
700
|
};
|
|
692
701
|
|
|
693
702
|
return <button onClick={sendTransaction}>Send SOL</button>;
|
|
@@ -709,7 +718,7 @@ import {
|
|
|
709
718
|
import { useSolana } from "@phantom/react-sdk";
|
|
710
719
|
|
|
711
720
|
function SolanaKitExample() {
|
|
712
|
-
const solana = useSolana();
|
|
721
|
+
const { solana } = useSolana();
|
|
713
722
|
|
|
714
723
|
const sendTransaction = async () => {
|
|
715
724
|
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
|
|
@@ -726,7 +735,7 @@ function SolanaKitExample() {
|
|
|
726
735
|
|
|
727
736
|
// Sign and send using chain-specific hook
|
|
728
737
|
const result = await solana.signAndSendTransaction(transaction);
|
|
729
|
-
console.log("Transaction sent:", result.
|
|
738
|
+
console.log("Transaction sent:", result.signature);
|
|
730
739
|
};
|
|
731
740
|
|
|
732
741
|
return <button onClick={sendTransaction}>Send SOL</button>;
|
|
@@ -740,7 +749,7 @@ import { parseEther, parseGwei, encodeFunctionData } from "viem";
|
|
|
740
749
|
import { useEthereum } from "@phantom/react-sdk";
|
|
741
750
|
|
|
742
751
|
function EthereumExample() {
|
|
743
|
-
const ethereum = useEthereum();
|
|
752
|
+
const { ethereum } = useEthereum();
|
|
744
753
|
|
|
745
754
|
const sendEth = async () => {
|
|
746
755
|
const result = await ethereum.sendTransaction({
|
|
@@ -780,16 +789,17 @@ function EthereumExample() {
|
|
|
780
789
|
|
|
781
790
|
Quick reference of all available hooks:
|
|
782
791
|
|
|
783
|
-
| Hook
|
|
784
|
-
|
|
|
785
|
-
| `useConnect`
|
|
786
|
-
| `useAccounts`
|
|
787
|
-
| `useIsExtensionInstalled`
|
|
788
|
-
| `
|
|
789
|
-
| `
|
|
790
|
-
| `
|
|
791
|
-
| `
|
|
792
|
-
| `
|
|
792
|
+
| Hook | Purpose | Returns |
|
|
793
|
+
| ----------------------------- | --------------------------------------- | --------------------------------------------------- |
|
|
794
|
+
| `useConnect` | Connect to wallet | `{ connect, isConnecting, error }` |
|
|
795
|
+
| `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
|
|
796
|
+
| `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
|
|
797
|
+
| `useIsPhantomLoginAvailable` | Check Phantom Login availability | `{ isLoading, isAvailable }` |
|
|
798
|
+
| `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
|
|
799
|
+
| `useAutoConfirm` | Auto-confirm management (injected only) | `{ enable, disable, status, supportedChains, ... }` |
|
|
800
|
+
| `useSolana` | Solana chain operations | `{ signMessage, signAndSendTransaction, ... }` |
|
|
801
|
+
| `useEthereum` | Ethereum chain operations | `{ signPersonalMessage, sendTransaction, ... }` |
|
|
802
|
+
| `usePhantom` | Get provider context | `{ isConnected, isReady }` |
|
|
793
803
|
|
|
794
804
|
## Configuration Reference
|
|
795
805
|
|
|
@@ -799,15 +809,16 @@ interface PhantomSDKConfig {
|
|
|
799
809
|
addressTypes?: [AddressType, ...AddressType[]]; // Networks to enable (e.g., [AddressType.solana])
|
|
800
810
|
|
|
801
811
|
// Required for embedded provider only
|
|
802
|
-
|
|
803
|
-
|
|
812
|
+
appId: string; // Your app ID from phantom.com/portal (required for embedded provider)
|
|
813
|
+
|
|
814
|
+
// Optional configuration
|
|
815
|
+
apiBaseUrl?: string; // Phantom API base URL (optional, has default)
|
|
804
816
|
authOptions?: {
|
|
805
|
-
authUrl?: string; // Custom auth URL (optional)
|
|
806
|
-
redirectUrl?: string; // Custom redirect URL (optional)
|
|
817
|
+
authUrl?: string; // Custom auth URL (optional, defaults to "https://connect.phantom.app/login")
|
|
818
|
+
redirectUrl?: string; // Custom redirect URL after authentication (optional)
|
|
807
819
|
};
|
|
808
|
-
embeddedWalletType?: "
|
|
809
|
-
|
|
810
|
-
autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (default: true for embedded, false for injected)
|
|
820
|
+
embeddedWalletType?: "user-wallet"; // Wallet type (optional, defaults to "user-wallet", currently the only supported type)
|
|
821
|
+
autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (optional, defaults to true for embedded, false for injected)
|
|
811
822
|
}
|
|
812
823
|
```
|
|
813
824
|
|
|
@@ -839,6 +850,7 @@ function App() {
|
|
|
839
850
|
// SDK configuration - static, won't change when debug settings change
|
|
840
851
|
const config: PhantomSDKConfig = {
|
|
841
852
|
providerType: "embedded",
|
|
853
|
+
appId: "your-app-id",
|
|
842
854
|
// ... other config
|
|
843
855
|
};
|
|
844
856
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { BrowserSDKConfig, DebugConfig, AuthOptions, BrowserSDK, WalletAddress, AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult } from '@phantom/browser-sdk';
|
|
4
|
-
export { AddressType, AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult, DebugLevel, DebugMessage, NetworkId, SignedTransaction, WalletAddress, debug } from '@phantom/browser-sdk';
|
|
3
|
+
import { BrowserSDKConfig, DebugConfig, AuthOptions, BrowserSDK, WalletAddress, ConnectResult, AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult } from '@phantom/browser-sdk';
|
|
4
|
+
export { AddressType, AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult, ConnectErrorEventData, ConnectEventData, ConnectStartEventData, DebugLevel, DebugMessage, DisconnectEventData, EmbeddedProviderEvent, EmbeddedProviderEventMap, EventCallback, NetworkId, SignedTransaction, WalletAddress, debug } from '@phantom/browser-sdk';
|
|
5
5
|
import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
|
|
6
|
-
import { ISolanaChain, IEthereumChain
|
|
7
|
-
export { EthTransactionRequest, IEthereumChain, ISolanaChain } from '@phantom/
|
|
6
|
+
import { ISolanaChain, IEthereumChain } from '@phantom/chain-interfaces';
|
|
7
|
+
export { EthTransactionRequest, IEthereumChain, ISolanaChain } from '@phantom/chain-interfaces';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
}
|
|
9
|
+
type PhantomSDKConfig = BrowserSDKConfig;
|
|
11
10
|
interface PhantomDebugConfig extends DebugConfig {
|
|
12
11
|
}
|
|
13
12
|
interface ConnectOptions {
|
|
@@ -21,9 +20,10 @@ interface PhantomContextValue {
|
|
|
21
20
|
isConnecting: boolean;
|
|
22
21
|
connectError: Error | null;
|
|
23
22
|
addresses: WalletAddress[];
|
|
24
|
-
walletId: string | null;
|
|
25
23
|
currentProviderType: "injected" | "embedded" | null;
|
|
26
24
|
isPhantomAvailable: boolean;
|
|
25
|
+
isClient: boolean;
|
|
26
|
+
user: ConnectResult | null;
|
|
27
27
|
}
|
|
28
28
|
interface PhantomProviderProps {
|
|
29
29
|
children: ReactNode;
|
|
@@ -34,7 +34,7 @@ declare function PhantomProvider({ children, config, debugConfig }: PhantomProvi
|
|
|
34
34
|
declare function usePhantom(): PhantomContextValue;
|
|
35
35
|
|
|
36
36
|
declare function useConnect(): {
|
|
37
|
-
connect: (options
|
|
37
|
+
connect: (options: AuthOptions) => Promise<_phantom_embedded_provider_core.ConnectResult>;
|
|
38
38
|
isConnecting: boolean;
|
|
39
39
|
error: Error | null;
|
|
40
40
|
currentProviderType: "injected" | "embedded" | null;
|
|
@@ -58,6 +58,15 @@ declare function useIsExtensionInstalled(): {
|
|
|
58
58
|
isInstalled: boolean;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* React hook to check if Phantom Login is available
|
|
63
|
+
* Checks if extension is installed and supports phantom_login feature
|
|
64
|
+
*/
|
|
65
|
+
declare function useIsPhantomLoginAvailable(): {
|
|
66
|
+
isLoading: boolean;
|
|
67
|
+
isAvailable: boolean;
|
|
68
|
+
};
|
|
69
|
+
|
|
61
70
|
interface UseAutoConfirmResult {
|
|
62
71
|
enable: (params: AutoConfirmEnableParams) => Promise<AutoConfirmResult>;
|
|
63
72
|
disable: () => Promise<void>;
|
|
@@ -72,53 +81,23 @@ declare function useAutoConfirm(): UseAutoConfirmResult;
|
|
|
72
81
|
/**
|
|
73
82
|
* Hook for Solana chain operations
|
|
74
83
|
*
|
|
75
|
-
* @returns Solana chain interface
|
|
84
|
+
* @returns Solana chain interface with connection enforcement
|
|
76
85
|
*/
|
|
77
86
|
declare function useSolana(): {
|
|
78
|
-
solana: ISolanaChain
|
|
79
|
-
signMessage: (message: string | Uint8Array) => Promise<{
|
|
80
|
-
signature: Uint8Array;
|
|
81
|
-
publicKey: string;
|
|
82
|
-
}>;
|
|
83
|
-
signTransaction: <T>(transaction: T) => Promise<T>;
|
|
84
|
-
signAndSendTransaction: <T>(transaction: T) => Promise<{
|
|
85
|
-
signature: string;
|
|
86
|
-
}>;
|
|
87
|
-
connect: (options?: {
|
|
88
|
-
onlyIfTrusted?: boolean;
|
|
89
|
-
}) => Promise<{
|
|
90
|
-
publicKey: string;
|
|
91
|
-
}>;
|
|
92
|
-
disconnect: () => Promise<void>;
|
|
93
|
-
switchNetwork: (network: "mainnet" | "devnet") => Promise<void | undefined>;
|
|
94
|
-
getPublicKey: () => Promise<string | null>;
|
|
87
|
+
solana: ISolanaChain;
|
|
95
88
|
isAvailable: boolean;
|
|
96
|
-
isConnected: boolean;
|
|
97
89
|
};
|
|
98
90
|
|
|
99
91
|
/**
|
|
100
92
|
* Hook for Ethereum chain operations
|
|
101
93
|
*
|
|
102
|
-
* @returns Ethereum chain interface
|
|
94
|
+
* @returns Ethereum chain interface with connection enforcement
|
|
103
95
|
*/
|
|
104
96
|
declare function useEthereum(): {
|
|
105
|
-
ethereum: IEthereumChain
|
|
106
|
-
request: <T = any>(args: {
|
|
107
|
-
method: string;
|
|
108
|
-
params?: unknown[];
|
|
109
|
-
}) => Promise<T>;
|
|
110
|
-
signPersonalMessage: (message: string, address: string) => Promise<string>;
|
|
111
|
-
signMessage: (message: string) => Promise<string>;
|
|
112
|
-
signTransaction: (transaction: EthTransactionRequest) => Promise<string>;
|
|
113
|
-
signTypedData: (typedData: any) => Promise<string>;
|
|
114
|
-
sendTransaction: (transaction: EthTransactionRequest) => Promise<string>;
|
|
115
|
-
switchChain: (chainId: number) => Promise<void>;
|
|
116
|
-
getChainId: () => Promise<number>;
|
|
117
|
-
getAccounts: () => Promise<string[]>;
|
|
97
|
+
ethereum: IEthereumChain;
|
|
118
98
|
isAvailable: boolean;
|
|
119
|
-
isConnected: boolean;
|
|
120
99
|
};
|
|
121
100
|
|
|
122
101
|
type ProviderType = "injected" | "embedded";
|
|
123
102
|
|
|
124
|
-
export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomProviderProps, PhantomSDKConfig, ProviderType, useAccounts, useAutoConfirm, useConnect, useDisconnect, useEthereum, useIsExtensionInstalled, usePhantom, useSolana };
|
|
103
|
+
export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomProviderProps, PhantomSDKConfig, ProviderType, useAccounts, useAutoConfirm, useConnect, useDisconnect, useEthereum, useIsExtensionInstalled, useIsPhantomLoginAvailable, usePhantom, useSolana };
|
package/dist/index.js
CHANGED
|
@@ -30,17 +30,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
|
-
AddressType: () =>
|
|
34
|
-
DebugLevel: () =>
|
|
35
|
-
NetworkId: () =>
|
|
33
|
+
AddressType: () => import_browser_sdk4.AddressType,
|
|
34
|
+
DebugLevel: () => import_browser_sdk4.DebugLevel,
|
|
35
|
+
NetworkId: () => import_browser_sdk4.NetworkId,
|
|
36
36
|
PhantomProvider: () => PhantomProvider,
|
|
37
|
-
debug: () =>
|
|
37
|
+
debug: () => import_browser_sdk4.debug,
|
|
38
38
|
useAccounts: () => useAccounts,
|
|
39
39
|
useAutoConfirm: () => useAutoConfirm,
|
|
40
40
|
useConnect: () => useConnect,
|
|
41
41
|
useDisconnect: () => useDisconnect,
|
|
42
42
|
useEthereum: () => useEthereum,
|
|
43
43
|
useIsExtensionInstalled: () => useIsExtensionInstalled,
|
|
44
|
+
useIsPhantomLoginAvailable: () => useIsPhantomLoginAvailable,
|
|
44
45
|
usePhantom: () => usePhantom,
|
|
45
46
|
useSolana: () => useSolana
|
|
46
47
|
});
|
|
@@ -52,42 +53,46 @@ var import_browser_sdk = require("@phantom/browser-sdk");
|
|
|
52
53
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
53
54
|
var PhantomContext = (0, import_react.createContext)(void 0);
|
|
54
55
|
function PhantomProvider({ children, config, debugConfig }) {
|
|
55
|
-
const memoizedConfig = (0, import_react.useMemo)(() =>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// Use providerType if provided, default to embedded
|
|
59
|
-
providerType: config.providerType || "embedded"
|
|
60
|
-
};
|
|
61
|
-
}, [config]);
|
|
56
|
+
const memoizedConfig = (0, import_react.useMemo)(() => config, [config]);
|
|
57
|
+
const [sdk, setSdk] = (0, import_react.useState)(null);
|
|
58
|
+
const [isClient, setIsClient] = (0, import_react.useState)(false);
|
|
62
59
|
const [isConnected, setIsConnected] = (0, import_react.useState)(false);
|
|
63
60
|
const [isConnecting, setIsConnecting] = (0, import_react.useState)(false);
|
|
64
61
|
const [connectError, setConnectError] = (0, import_react.useState)(null);
|
|
65
62
|
const [addresses, setAddresses] = (0, import_react.useState)([]);
|
|
66
|
-
const [walletId, setWalletId] = (0, import_react.useState)(null);
|
|
67
63
|
const [currentProviderType, setCurrentProviderType] = (0, import_react.useState)(
|
|
68
64
|
memoizedConfig.providerType || null
|
|
69
65
|
);
|
|
70
66
|
const [isPhantomAvailable, setIsPhantomAvailable] = (0, import_react.useState)(false);
|
|
71
|
-
const [
|
|
67
|
+
const [user, setUser] = (0, import_react.useState)(null);
|
|
68
|
+
(0, import_react.useEffect)(() => {
|
|
69
|
+
setIsClient(true);
|
|
70
|
+
}, []);
|
|
72
71
|
(0, import_react.useEffect)(() => {
|
|
72
|
+
if (!isClient)
|
|
73
|
+
return;
|
|
73
74
|
const sdkInstance = new import_browser_sdk.BrowserSDK(memoizedConfig);
|
|
75
|
+
setSdk(sdkInstance);
|
|
76
|
+
}, [isClient, memoizedConfig]);
|
|
77
|
+
(0, import_react.useEffect)(() => {
|
|
78
|
+
if (!sdk)
|
|
79
|
+
return;
|
|
74
80
|
const handleConnectStart = () => {
|
|
75
81
|
setIsConnecting(true);
|
|
76
82
|
setConnectError(null);
|
|
77
83
|
};
|
|
78
|
-
const handleConnect = async () => {
|
|
84
|
+
const handleConnect = async (data) => {
|
|
79
85
|
try {
|
|
80
86
|
setIsConnected(true);
|
|
81
87
|
setIsConnecting(false);
|
|
82
|
-
|
|
83
|
-
setCurrentProviderType(
|
|
84
|
-
const addrs = await
|
|
88
|
+
setUser(data);
|
|
89
|
+
setCurrentProviderType(data.providerType || null);
|
|
90
|
+
const addrs = await sdk.getAddresses();
|
|
85
91
|
setAddresses(addrs);
|
|
86
|
-
setWalletId(sdkInstance.getWalletId());
|
|
87
92
|
} catch (err) {
|
|
88
93
|
console.error("Error connecting:", err);
|
|
89
94
|
try {
|
|
90
|
-
await
|
|
95
|
+
await sdk.disconnect();
|
|
91
96
|
} catch (err2) {
|
|
92
97
|
console.error("Error disconnecting:", err2);
|
|
93
98
|
}
|
|
@@ -97,33 +102,33 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
97
102
|
setIsConnecting(false);
|
|
98
103
|
setIsConnected(false);
|
|
99
104
|
setConnectError(new Error(errorData.error || "Connection failed"));
|
|
105
|
+
setAddresses([]);
|
|
100
106
|
};
|
|
101
107
|
const handleDisconnect = () => {
|
|
102
108
|
setIsConnected(false);
|
|
103
109
|
setIsConnecting(false);
|
|
104
110
|
setConnectError(null);
|
|
105
111
|
setAddresses([]);
|
|
106
|
-
|
|
112
|
+
setUser(null);
|
|
107
113
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
setSdk(sdkInstance);
|
|
114
|
+
sdk.on("connect_start", handleConnectStart);
|
|
115
|
+
sdk.on("connect", handleConnect);
|
|
116
|
+
sdk.on("connect_error", handleConnectError);
|
|
117
|
+
sdk.on("disconnect", handleDisconnect);
|
|
113
118
|
return () => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
sdk.off("connect_start", handleConnectStart);
|
|
120
|
+
sdk.off("connect", handleConnect);
|
|
121
|
+
sdk.off("connect_error", handleConnectError);
|
|
122
|
+
sdk.off("disconnect", handleDisconnect);
|
|
118
123
|
};
|
|
119
|
-
}, [
|
|
124
|
+
}, [sdk]);
|
|
120
125
|
(0, import_react.useEffect)(() => {
|
|
121
|
-
if (!
|
|
126
|
+
if (!debugConfig || !sdk)
|
|
122
127
|
return;
|
|
123
128
|
sdk.configureDebug(debugConfig);
|
|
124
129
|
}, [sdk, debugConfig]);
|
|
125
130
|
(0, import_react.useEffect)(() => {
|
|
126
|
-
if (!sdk)
|
|
131
|
+
if (!isClient || !sdk)
|
|
127
132
|
return;
|
|
128
133
|
const initialize = async () => {
|
|
129
134
|
try {
|
|
@@ -139,7 +144,7 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
139
144
|
}
|
|
140
145
|
};
|
|
141
146
|
initialize();
|
|
142
|
-
}, [sdk, memoizedConfig.autoConnect]);
|
|
147
|
+
}, [sdk, memoizedConfig.autoConnect, isClient]);
|
|
143
148
|
const value = (0, import_react.useMemo)(
|
|
144
149
|
() => ({
|
|
145
150
|
sdk,
|
|
@@ -147,11 +152,12 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
147
152
|
isConnecting,
|
|
148
153
|
connectError,
|
|
149
154
|
addresses,
|
|
150
|
-
walletId,
|
|
151
155
|
currentProviderType,
|
|
152
|
-
isPhantomAvailable
|
|
156
|
+
isPhantomAvailable,
|
|
157
|
+
isClient,
|
|
158
|
+
user
|
|
153
159
|
}),
|
|
154
|
-
[sdk, isConnected, isConnecting, connectError, addresses,
|
|
160
|
+
[sdk, isConnected, isConnecting, connectError, addresses, currentProviderType, isPhantomAvailable, isClient, user]
|
|
155
161
|
);
|
|
156
162
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PhantomContext.Provider, { value, children });
|
|
157
163
|
}
|
|
@@ -258,6 +264,39 @@ function useIsExtensionInstalled() {
|
|
|
258
264
|
return { isLoading, isInstalled };
|
|
259
265
|
}
|
|
260
266
|
|
|
267
|
+
// src/hooks/useIsPhantomLoginAvailable.ts
|
|
268
|
+
var React2 = __toESM(require("react"));
|
|
269
|
+
var import_browser_sdk3 = require("@phantom/browser-sdk");
|
|
270
|
+
function useIsPhantomLoginAvailable() {
|
|
271
|
+
const [isLoading, setIsLoading] = React2.useState(true);
|
|
272
|
+
const [isAvailable, setIsAvailable] = React2.useState(false);
|
|
273
|
+
React2.useEffect(() => {
|
|
274
|
+
let isMounted = true;
|
|
275
|
+
const checkPhantomLogin = async () => {
|
|
276
|
+
try {
|
|
277
|
+
setIsLoading(true);
|
|
278
|
+
const result = await (0, import_browser_sdk3.isPhantomLoginAvailable)(3e3);
|
|
279
|
+
if (isMounted) {
|
|
280
|
+
setIsAvailable(result);
|
|
281
|
+
}
|
|
282
|
+
} catch (error) {
|
|
283
|
+
if (isMounted) {
|
|
284
|
+
setIsAvailable(false);
|
|
285
|
+
}
|
|
286
|
+
} finally {
|
|
287
|
+
if (isMounted) {
|
|
288
|
+
setIsLoading(false);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
checkPhantomLogin();
|
|
293
|
+
return () => {
|
|
294
|
+
isMounted = false;
|
|
295
|
+
};
|
|
296
|
+
}, []);
|
|
297
|
+
return { isLoading, isAvailable };
|
|
298
|
+
}
|
|
299
|
+
|
|
261
300
|
// src/hooks/useAutoConfirm.ts
|
|
262
301
|
var import_react4 = require("react");
|
|
263
302
|
function useAutoConfirm() {
|
|
@@ -353,189 +392,40 @@ function useAutoConfirm() {
|
|
|
353
392
|
}
|
|
354
393
|
|
|
355
394
|
// src/hooks/useSolana.ts
|
|
356
|
-
var import_react5 = require("react");
|
|
357
395
|
function useSolana() {
|
|
358
|
-
const { sdk, isConnected } = usePhantom();
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
const solanaChain = (0, import_react5.useMemo)(() => {
|
|
367
|
-
if (!sdk || !isConnected)
|
|
368
|
-
return null;
|
|
369
|
-
try {
|
|
370
|
-
return sdk.solana;
|
|
371
|
-
} catch {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
}, [sdk, isConnected]);
|
|
375
|
-
const signMessage = (0, import_react5.useCallback)(
|
|
376
|
-
async (message) => {
|
|
377
|
-
const chain = getSolanaChain();
|
|
378
|
-
return chain.signMessage(message);
|
|
379
|
-
},
|
|
380
|
-
[getSolanaChain]
|
|
381
|
-
);
|
|
382
|
-
const signTransaction = (0, import_react5.useCallback)(
|
|
383
|
-
async (transaction) => {
|
|
384
|
-
const chain = getSolanaChain();
|
|
385
|
-
return chain.signTransaction(transaction);
|
|
386
|
-
},
|
|
387
|
-
[getSolanaChain]
|
|
388
|
-
);
|
|
389
|
-
const signAndSendTransaction = (0, import_react5.useCallback)(
|
|
390
|
-
async (transaction) => {
|
|
391
|
-
const chain = getSolanaChain();
|
|
392
|
-
return chain.signAndSendTransaction(transaction);
|
|
393
|
-
},
|
|
394
|
-
[getSolanaChain]
|
|
395
|
-
);
|
|
396
|
-
const connect = (0, import_react5.useCallback)(
|
|
397
|
-
async (options) => {
|
|
398
|
-
const chain = getSolanaChain();
|
|
399
|
-
return chain.connect(options);
|
|
400
|
-
},
|
|
401
|
-
[getSolanaChain]
|
|
402
|
-
);
|
|
403
|
-
const disconnect = (0, import_react5.useCallback)(async () => {
|
|
404
|
-
const chain = getSolanaChain();
|
|
405
|
-
return chain.disconnect();
|
|
406
|
-
}, [getSolanaChain]);
|
|
407
|
-
const switchNetwork = (0, import_react5.useCallback)(
|
|
408
|
-
async (network) => {
|
|
409
|
-
const chain = getSolanaChain();
|
|
410
|
-
return chain.switchNetwork?.(network);
|
|
411
|
-
},
|
|
412
|
-
[getSolanaChain]
|
|
413
|
-
);
|
|
414
|
-
const getPublicKey = (0, import_react5.useCallback)(async () => {
|
|
415
|
-
if (!sdk || !sdk.isConnected())
|
|
416
|
-
return null;
|
|
417
|
-
return sdk.solana.getPublicKey();
|
|
418
|
-
}, [sdk]);
|
|
396
|
+
const { sdk, isConnected, isClient } = usePhantom();
|
|
397
|
+
if (!isClient || !sdk) {
|
|
398
|
+
return {
|
|
399
|
+
solana: {},
|
|
400
|
+
// This will be replaced when SDK is ready
|
|
401
|
+
isAvailable: false
|
|
402
|
+
};
|
|
403
|
+
}
|
|
419
404
|
return {
|
|
420
|
-
// Chain instance for
|
|
421
|
-
solana:
|
|
422
|
-
// Convenient methods
|
|
423
|
-
signMessage,
|
|
424
|
-
signTransaction,
|
|
425
|
-
signAndSendTransaction,
|
|
426
|
-
connect,
|
|
427
|
-
disconnect,
|
|
428
|
-
switchNetwork,
|
|
429
|
-
getPublicKey,
|
|
405
|
+
// Chain instance with connection enforcement for signing methods
|
|
406
|
+
solana: sdk.solana,
|
|
430
407
|
// State
|
|
431
|
-
isAvailable: !!
|
|
432
|
-
isConnected: solanaChain?.isConnected() ?? false
|
|
408
|
+
isAvailable: !!isConnected
|
|
433
409
|
};
|
|
434
410
|
}
|
|
435
411
|
|
|
436
412
|
// src/hooks/useEthereum.ts
|
|
437
|
-
var import_react6 = require("react");
|
|
438
413
|
function useEthereum() {
|
|
439
|
-
const { sdk, isConnected } = usePhantom();
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}
|
|
447
|
-
const ethereumChain = (0, import_react6.useMemo)(() => {
|
|
448
|
-
if (!sdk || !isConnected)
|
|
449
|
-
return null;
|
|
450
|
-
try {
|
|
451
|
-
return sdk.ethereum;
|
|
452
|
-
} catch {
|
|
453
|
-
return null;
|
|
454
|
-
}
|
|
455
|
-
}, [sdk, isConnected]);
|
|
456
|
-
const request = (0, import_react6.useCallback)(
|
|
457
|
-
async (args) => {
|
|
458
|
-
const chain = getEthereumChain();
|
|
459
|
-
return chain.request(args);
|
|
460
|
-
},
|
|
461
|
-
[getEthereumChain]
|
|
462
|
-
);
|
|
463
|
-
const signPersonalMessage = (0, import_react6.useCallback)(
|
|
464
|
-
async (message, address) => {
|
|
465
|
-
return request({
|
|
466
|
-
method: "personal_sign",
|
|
467
|
-
params: [message, address]
|
|
468
|
-
});
|
|
469
|
-
},
|
|
470
|
-
[request]
|
|
471
|
-
);
|
|
472
|
-
const signTransaction = (0, import_react6.useCallback)(
|
|
473
|
-
async (transaction) => {
|
|
474
|
-
const chain = getEthereumChain();
|
|
475
|
-
return chain.signTransaction(transaction);
|
|
476
|
-
},
|
|
477
|
-
[getEthereumChain]
|
|
478
|
-
);
|
|
479
|
-
const sendTransaction = (0, import_react6.useCallback)(
|
|
480
|
-
async (transaction) => {
|
|
481
|
-
const chain = getEthereumChain();
|
|
482
|
-
return chain.sendTransaction(transaction);
|
|
483
|
-
},
|
|
484
|
-
[getEthereumChain]
|
|
485
|
-
);
|
|
486
|
-
const switchChain = (0, import_react6.useCallback)(
|
|
487
|
-
async (chainId) => {
|
|
488
|
-
const chain = getEthereumChain();
|
|
489
|
-
return chain.switchChain(chainId);
|
|
490
|
-
},
|
|
491
|
-
[getEthereumChain]
|
|
492
|
-
);
|
|
493
|
-
const getChainId = (0, import_react6.useCallback)(async () => {
|
|
494
|
-
const chain = getEthereumChain();
|
|
495
|
-
return chain.getChainId();
|
|
496
|
-
}, [getEthereumChain]);
|
|
497
|
-
const getAccounts = (0, import_react6.useCallback)(async () => {
|
|
498
|
-
const chain = getEthereumChain();
|
|
499
|
-
return chain.getAccounts();
|
|
500
|
-
}, [getEthereumChain]);
|
|
501
|
-
const signMessage = (0, import_react6.useCallback)(
|
|
502
|
-
async (message) => {
|
|
503
|
-
return request({
|
|
504
|
-
method: "eth_sign",
|
|
505
|
-
params: [await getAccounts().then((accounts) => accounts[0]), message]
|
|
506
|
-
});
|
|
507
|
-
},
|
|
508
|
-
[request, getAccounts]
|
|
509
|
-
);
|
|
510
|
-
const signTypedData = (0, import_react6.useCallback)(
|
|
511
|
-
async (typedData) => {
|
|
512
|
-
const accounts = await getAccounts();
|
|
513
|
-
return request({
|
|
514
|
-
method: "eth_signTypedData_v4",
|
|
515
|
-
params: [accounts[0], JSON.stringify(typedData)]
|
|
516
|
-
});
|
|
517
|
-
},
|
|
518
|
-
[request, getAccounts]
|
|
519
|
-
);
|
|
414
|
+
const { sdk, isConnected, isClient } = usePhantom();
|
|
415
|
+
if (!isClient || !sdk) {
|
|
416
|
+
return {
|
|
417
|
+
ethereum: {},
|
|
418
|
+
// This will be replaced when SDK is ready
|
|
419
|
+
isAvailable: false
|
|
420
|
+
};
|
|
421
|
+
}
|
|
520
422
|
return {
|
|
521
|
-
// Chain instance for
|
|
522
|
-
ethereum:
|
|
523
|
-
// Standard EIP-1193 interface
|
|
524
|
-
request,
|
|
525
|
-
// Convenient methods
|
|
526
|
-
signPersonalMessage,
|
|
527
|
-
signMessage,
|
|
528
|
-
signTransaction,
|
|
529
|
-
signTypedData,
|
|
530
|
-
sendTransaction,
|
|
531
|
-
switchChain,
|
|
532
|
-
getChainId,
|
|
533
|
-
getAccounts,
|
|
423
|
+
// Chain instance with connection enforcement for signing methods
|
|
424
|
+
ethereum: sdk.ethereum,
|
|
534
425
|
// State
|
|
535
|
-
isAvailable: !!
|
|
536
|
-
isConnected: ethereumChain?.isConnected() ?? false
|
|
426
|
+
isAvailable: !!isConnected
|
|
537
427
|
};
|
|
538
428
|
}
|
|
539
429
|
|
|
540
430
|
// src/index.ts
|
|
541
|
-
var
|
|
431
|
+
var import_browser_sdk4 = require("@phantom/browser-sdk");
|
package/dist/index.mjs
CHANGED
|
@@ -4,42 +4,46 @@ import { BrowserSDK } from "@phantom/browser-sdk";
|
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
var PhantomContext = createContext(void 0);
|
|
6
6
|
function PhantomProvider({ children, config, debugConfig }) {
|
|
7
|
-
const memoizedConfig = useMemo(() =>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Use providerType if provided, default to embedded
|
|
11
|
-
providerType: config.providerType || "embedded"
|
|
12
|
-
};
|
|
13
|
-
}, [config]);
|
|
7
|
+
const memoizedConfig = useMemo(() => config, [config]);
|
|
8
|
+
const [sdk, setSdk] = useState(null);
|
|
9
|
+
const [isClient, setIsClient] = useState(false);
|
|
14
10
|
const [isConnected, setIsConnected] = useState(false);
|
|
15
11
|
const [isConnecting, setIsConnecting] = useState(false);
|
|
16
12
|
const [connectError, setConnectError] = useState(null);
|
|
17
13
|
const [addresses, setAddresses] = useState([]);
|
|
18
|
-
const [walletId, setWalletId] = useState(null);
|
|
19
14
|
const [currentProviderType, setCurrentProviderType] = useState(
|
|
20
15
|
memoizedConfig.providerType || null
|
|
21
16
|
);
|
|
22
17
|
const [isPhantomAvailable, setIsPhantomAvailable] = useState(false);
|
|
23
|
-
const [
|
|
18
|
+
const [user, setUser] = useState(null);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setIsClient(true);
|
|
21
|
+
}, []);
|
|
24
22
|
useEffect(() => {
|
|
23
|
+
if (!isClient)
|
|
24
|
+
return;
|
|
25
25
|
const sdkInstance = new BrowserSDK(memoizedConfig);
|
|
26
|
+
setSdk(sdkInstance);
|
|
27
|
+
}, [isClient, memoizedConfig]);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!sdk)
|
|
30
|
+
return;
|
|
26
31
|
const handleConnectStart = () => {
|
|
27
32
|
setIsConnecting(true);
|
|
28
33
|
setConnectError(null);
|
|
29
34
|
};
|
|
30
|
-
const handleConnect = async () => {
|
|
35
|
+
const handleConnect = async (data) => {
|
|
31
36
|
try {
|
|
32
37
|
setIsConnected(true);
|
|
33
38
|
setIsConnecting(false);
|
|
34
|
-
|
|
35
|
-
setCurrentProviderType(
|
|
36
|
-
const addrs = await
|
|
39
|
+
setUser(data);
|
|
40
|
+
setCurrentProviderType(data.providerType || null);
|
|
41
|
+
const addrs = await sdk.getAddresses();
|
|
37
42
|
setAddresses(addrs);
|
|
38
|
-
setWalletId(sdkInstance.getWalletId());
|
|
39
43
|
} catch (err) {
|
|
40
44
|
console.error("Error connecting:", err);
|
|
41
45
|
try {
|
|
42
|
-
await
|
|
46
|
+
await sdk.disconnect();
|
|
43
47
|
} catch (err2) {
|
|
44
48
|
console.error("Error disconnecting:", err2);
|
|
45
49
|
}
|
|
@@ -49,33 +53,33 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
49
53
|
setIsConnecting(false);
|
|
50
54
|
setIsConnected(false);
|
|
51
55
|
setConnectError(new Error(errorData.error || "Connection failed"));
|
|
56
|
+
setAddresses([]);
|
|
52
57
|
};
|
|
53
58
|
const handleDisconnect = () => {
|
|
54
59
|
setIsConnected(false);
|
|
55
60
|
setIsConnecting(false);
|
|
56
61
|
setConnectError(null);
|
|
57
62
|
setAddresses([]);
|
|
58
|
-
|
|
63
|
+
setUser(null);
|
|
59
64
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
setSdk(sdkInstance);
|
|
65
|
+
sdk.on("connect_start", handleConnectStart);
|
|
66
|
+
sdk.on("connect", handleConnect);
|
|
67
|
+
sdk.on("connect_error", handleConnectError);
|
|
68
|
+
sdk.on("disconnect", handleDisconnect);
|
|
65
69
|
return () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
sdk.off("connect_start", handleConnectStart);
|
|
71
|
+
sdk.off("connect", handleConnect);
|
|
72
|
+
sdk.off("connect_error", handleConnectError);
|
|
73
|
+
sdk.off("disconnect", handleDisconnect);
|
|
70
74
|
};
|
|
71
|
-
}, [
|
|
75
|
+
}, [sdk]);
|
|
72
76
|
useEffect(() => {
|
|
73
|
-
if (!
|
|
77
|
+
if (!debugConfig || !sdk)
|
|
74
78
|
return;
|
|
75
79
|
sdk.configureDebug(debugConfig);
|
|
76
80
|
}, [sdk, debugConfig]);
|
|
77
81
|
useEffect(() => {
|
|
78
|
-
if (!sdk)
|
|
82
|
+
if (!isClient || !sdk)
|
|
79
83
|
return;
|
|
80
84
|
const initialize = async () => {
|
|
81
85
|
try {
|
|
@@ -91,7 +95,7 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
91
95
|
}
|
|
92
96
|
};
|
|
93
97
|
initialize();
|
|
94
|
-
}, [sdk, memoizedConfig.autoConnect]);
|
|
98
|
+
}, [sdk, memoizedConfig.autoConnect, isClient]);
|
|
95
99
|
const value = useMemo(
|
|
96
100
|
() => ({
|
|
97
101
|
sdk,
|
|
@@ -99,11 +103,12 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
99
103
|
isConnecting,
|
|
100
104
|
connectError,
|
|
101
105
|
addresses,
|
|
102
|
-
walletId,
|
|
103
106
|
currentProviderType,
|
|
104
|
-
isPhantomAvailable
|
|
107
|
+
isPhantomAvailable,
|
|
108
|
+
isClient,
|
|
109
|
+
user
|
|
105
110
|
}),
|
|
106
|
-
[sdk, isConnected, isConnecting, connectError, addresses,
|
|
111
|
+
[sdk, isConnected, isConnecting, connectError, addresses, currentProviderType, isPhantomAvailable, isClient, user]
|
|
107
112
|
);
|
|
108
113
|
return /* @__PURE__ */ jsx(PhantomContext.Provider, { value, children });
|
|
109
114
|
}
|
|
@@ -210,14 +215,47 @@ function useIsExtensionInstalled() {
|
|
|
210
215
|
return { isLoading, isInstalled };
|
|
211
216
|
}
|
|
212
217
|
|
|
218
|
+
// src/hooks/useIsPhantomLoginAvailable.ts
|
|
219
|
+
import * as React2 from "react";
|
|
220
|
+
import { isPhantomLoginAvailable } from "@phantom/browser-sdk";
|
|
221
|
+
function useIsPhantomLoginAvailable() {
|
|
222
|
+
const [isLoading, setIsLoading] = React2.useState(true);
|
|
223
|
+
const [isAvailable, setIsAvailable] = React2.useState(false);
|
|
224
|
+
React2.useEffect(() => {
|
|
225
|
+
let isMounted = true;
|
|
226
|
+
const checkPhantomLogin = async () => {
|
|
227
|
+
try {
|
|
228
|
+
setIsLoading(true);
|
|
229
|
+
const result = await isPhantomLoginAvailable(3e3);
|
|
230
|
+
if (isMounted) {
|
|
231
|
+
setIsAvailable(result);
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
if (isMounted) {
|
|
235
|
+
setIsAvailable(false);
|
|
236
|
+
}
|
|
237
|
+
} finally {
|
|
238
|
+
if (isMounted) {
|
|
239
|
+
setIsLoading(false);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
checkPhantomLogin();
|
|
244
|
+
return () => {
|
|
245
|
+
isMounted = false;
|
|
246
|
+
};
|
|
247
|
+
}, []);
|
|
248
|
+
return { isLoading, isAvailable };
|
|
249
|
+
}
|
|
250
|
+
|
|
213
251
|
// src/hooks/useAutoConfirm.ts
|
|
214
|
-
import { useCallback as useCallback3, useState as
|
|
252
|
+
import { useCallback as useCallback3, useState as useState5, useEffect as useEffect4 } from "react";
|
|
215
253
|
function useAutoConfirm() {
|
|
216
254
|
const { sdk, currentProviderType } = usePhantom();
|
|
217
|
-
const [status, setStatus] =
|
|
218
|
-
const [supportedChains, setSupportedChains] =
|
|
219
|
-
const [isLoading, setIsLoading] =
|
|
220
|
-
const [error, setError] =
|
|
255
|
+
const [status, setStatus] = useState5(null);
|
|
256
|
+
const [supportedChains, setSupportedChains] = useState5(null);
|
|
257
|
+
const [isLoading, setIsLoading] = useState5(false);
|
|
258
|
+
const [error, setError] = useState5(null);
|
|
221
259
|
const isInjected = currentProviderType === "injected";
|
|
222
260
|
const enable = useCallback3(
|
|
223
261
|
async (params) => {
|
|
@@ -284,7 +322,7 @@ function useAutoConfirm() {
|
|
|
284
322
|
setIsLoading(false);
|
|
285
323
|
}
|
|
286
324
|
}, [sdk, isInjected]);
|
|
287
|
-
|
|
325
|
+
useEffect4(() => {
|
|
288
326
|
if (sdk && isInjected) {
|
|
289
327
|
refetch();
|
|
290
328
|
} else {
|
|
@@ -305,187 +343,38 @@ function useAutoConfirm() {
|
|
|
305
343
|
}
|
|
306
344
|
|
|
307
345
|
// src/hooks/useSolana.ts
|
|
308
|
-
import { useCallback as useCallback4, useMemo as useMemo2 } from "react";
|
|
309
346
|
function useSolana() {
|
|
310
|
-
const { sdk, isConnected } = usePhantom();
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
const solanaChain = useMemo2(() => {
|
|
319
|
-
if (!sdk || !isConnected)
|
|
320
|
-
return null;
|
|
321
|
-
try {
|
|
322
|
-
return sdk.solana;
|
|
323
|
-
} catch {
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
}, [sdk, isConnected]);
|
|
327
|
-
const signMessage = useCallback4(
|
|
328
|
-
async (message) => {
|
|
329
|
-
const chain = getSolanaChain();
|
|
330
|
-
return chain.signMessage(message);
|
|
331
|
-
},
|
|
332
|
-
[getSolanaChain]
|
|
333
|
-
);
|
|
334
|
-
const signTransaction = useCallback4(
|
|
335
|
-
async (transaction) => {
|
|
336
|
-
const chain = getSolanaChain();
|
|
337
|
-
return chain.signTransaction(transaction);
|
|
338
|
-
},
|
|
339
|
-
[getSolanaChain]
|
|
340
|
-
);
|
|
341
|
-
const signAndSendTransaction = useCallback4(
|
|
342
|
-
async (transaction) => {
|
|
343
|
-
const chain = getSolanaChain();
|
|
344
|
-
return chain.signAndSendTransaction(transaction);
|
|
345
|
-
},
|
|
346
|
-
[getSolanaChain]
|
|
347
|
-
);
|
|
348
|
-
const connect = useCallback4(
|
|
349
|
-
async (options) => {
|
|
350
|
-
const chain = getSolanaChain();
|
|
351
|
-
return chain.connect(options);
|
|
352
|
-
},
|
|
353
|
-
[getSolanaChain]
|
|
354
|
-
);
|
|
355
|
-
const disconnect = useCallback4(async () => {
|
|
356
|
-
const chain = getSolanaChain();
|
|
357
|
-
return chain.disconnect();
|
|
358
|
-
}, [getSolanaChain]);
|
|
359
|
-
const switchNetwork = useCallback4(
|
|
360
|
-
async (network) => {
|
|
361
|
-
const chain = getSolanaChain();
|
|
362
|
-
return chain.switchNetwork?.(network);
|
|
363
|
-
},
|
|
364
|
-
[getSolanaChain]
|
|
365
|
-
);
|
|
366
|
-
const getPublicKey = useCallback4(async () => {
|
|
367
|
-
if (!sdk || !sdk.isConnected())
|
|
368
|
-
return null;
|
|
369
|
-
return sdk.solana.getPublicKey();
|
|
370
|
-
}, [sdk]);
|
|
347
|
+
const { sdk, isConnected, isClient } = usePhantom();
|
|
348
|
+
if (!isClient || !sdk) {
|
|
349
|
+
return {
|
|
350
|
+
solana: {},
|
|
351
|
+
// This will be replaced when SDK is ready
|
|
352
|
+
isAvailable: false
|
|
353
|
+
};
|
|
354
|
+
}
|
|
371
355
|
return {
|
|
372
|
-
// Chain instance for
|
|
373
|
-
solana:
|
|
374
|
-
// Convenient methods
|
|
375
|
-
signMessage,
|
|
376
|
-
signTransaction,
|
|
377
|
-
signAndSendTransaction,
|
|
378
|
-
connect,
|
|
379
|
-
disconnect,
|
|
380
|
-
switchNetwork,
|
|
381
|
-
getPublicKey,
|
|
356
|
+
// Chain instance with connection enforcement for signing methods
|
|
357
|
+
solana: sdk.solana,
|
|
382
358
|
// State
|
|
383
|
-
isAvailable: !!
|
|
384
|
-
isConnected: solanaChain?.isConnected() ?? false
|
|
359
|
+
isAvailable: !!isConnected
|
|
385
360
|
};
|
|
386
361
|
}
|
|
387
362
|
|
|
388
363
|
// src/hooks/useEthereum.ts
|
|
389
|
-
import { useCallback as useCallback5, useMemo as useMemo3 } from "react";
|
|
390
364
|
function useEthereum() {
|
|
391
|
-
const { sdk, isConnected } = usePhantom();
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
const ethereumChain = useMemo3(() => {
|
|
400
|
-
if (!sdk || !isConnected)
|
|
401
|
-
return null;
|
|
402
|
-
try {
|
|
403
|
-
return sdk.ethereum;
|
|
404
|
-
} catch {
|
|
405
|
-
return null;
|
|
406
|
-
}
|
|
407
|
-
}, [sdk, isConnected]);
|
|
408
|
-
const request = useCallback5(
|
|
409
|
-
async (args) => {
|
|
410
|
-
const chain = getEthereumChain();
|
|
411
|
-
return chain.request(args);
|
|
412
|
-
},
|
|
413
|
-
[getEthereumChain]
|
|
414
|
-
);
|
|
415
|
-
const signPersonalMessage = useCallback5(
|
|
416
|
-
async (message, address) => {
|
|
417
|
-
return request({
|
|
418
|
-
method: "personal_sign",
|
|
419
|
-
params: [message, address]
|
|
420
|
-
});
|
|
421
|
-
},
|
|
422
|
-
[request]
|
|
423
|
-
);
|
|
424
|
-
const signTransaction = useCallback5(
|
|
425
|
-
async (transaction) => {
|
|
426
|
-
const chain = getEthereumChain();
|
|
427
|
-
return chain.signTransaction(transaction);
|
|
428
|
-
},
|
|
429
|
-
[getEthereumChain]
|
|
430
|
-
);
|
|
431
|
-
const sendTransaction = useCallback5(
|
|
432
|
-
async (transaction) => {
|
|
433
|
-
const chain = getEthereumChain();
|
|
434
|
-
return chain.sendTransaction(transaction);
|
|
435
|
-
},
|
|
436
|
-
[getEthereumChain]
|
|
437
|
-
);
|
|
438
|
-
const switchChain = useCallback5(
|
|
439
|
-
async (chainId) => {
|
|
440
|
-
const chain = getEthereumChain();
|
|
441
|
-
return chain.switchChain(chainId);
|
|
442
|
-
},
|
|
443
|
-
[getEthereumChain]
|
|
444
|
-
);
|
|
445
|
-
const getChainId = useCallback5(async () => {
|
|
446
|
-
const chain = getEthereumChain();
|
|
447
|
-
return chain.getChainId();
|
|
448
|
-
}, [getEthereumChain]);
|
|
449
|
-
const getAccounts = useCallback5(async () => {
|
|
450
|
-
const chain = getEthereumChain();
|
|
451
|
-
return chain.getAccounts();
|
|
452
|
-
}, [getEthereumChain]);
|
|
453
|
-
const signMessage = useCallback5(
|
|
454
|
-
async (message) => {
|
|
455
|
-
return request({
|
|
456
|
-
method: "eth_sign",
|
|
457
|
-
params: [await getAccounts().then((accounts) => accounts[0]), message]
|
|
458
|
-
});
|
|
459
|
-
},
|
|
460
|
-
[request, getAccounts]
|
|
461
|
-
);
|
|
462
|
-
const signTypedData = useCallback5(
|
|
463
|
-
async (typedData) => {
|
|
464
|
-
const accounts = await getAccounts();
|
|
465
|
-
return request({
|
|
466
|
-
method: "eth_signTypedData_v4",
|
|
467
|
-
params: [accounts[0], JSON.stringify(typedData)]
|
|
468
|
-
});
|
|
469
|
-
},
|
|
470
|
-
[request, getAccounts]
|
|
471
|
-
);
|
|
365
|
+
const { sdk, isConnected, isClient } = usePhantom();
|
|
366
|
+
if (!isClient || !sdk) {
|
|
367
|
+
return {
|
|
368
|
+
ethereum: {},
|
|
369
|
+
// This will be replaced when SDK is ready
|
|
370
|
+
isAvailable: false
|
|
371
|
+
};
|
|
372
|
+
}
|
|
472
373
|
return {
|
|
473
|
-
// Chain instance for
|
|
474
|
-
ethereum:
|
|
475
|
-
// Standard EIP-1193 interface
|
|
476
|
-
request,
|
|
477
|
-
// Convenient methods
|
|
478
|
-
signPersonalMessage,
|
|
479
|
-
signMessage,
|
|
480
|
-
signTransaction,
|
|
481
|
-
signTypedData,
|
|
482
|
-
sendTransaction,
|
|
483
|
-
switchChain,
|
|
484
|
-
getChainId,
|
|
485
|
-
getAccounts,
|
|
374
|
+
// Chain instance with connection enforcement for signing methods
|
|
375
|
+
ethereum: sdk.ethereum,
|
|
486
376
|
// State
|
|
487
|
-
isAvailable: !!
|
|
488
|
-
isConnected: ethereumChain?.isConnected() ?? false
|
|
377
|
+
isAvailable: !!isConnected
|
|
489
378
|
};
|
|
490
379
|
}
|
|
491
380
|
|
|
@@ -503,6 +392,7 @@ export {
|
|
|
503
392
|
useDisconnect,
|
|
504
393
|
useEthereum,
|
|
505
394
|
useIsExtensionInstalled,
|
|
395
|
+
useIsPhantomLoginAvailable,
|
|
506
396
|
usePhantom,
|
|
507
397
|
useSolana
|
|
508
398
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/react-sdk",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.21",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"prettier": "prettier --write \"src/**/*.{ts,tsx}\""
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@phantom/browser-sdk": "^1.0.0-beta.
|
|
30
|
-
"@phantom/
|
|
31
|
-
"@phantom/constants": "^1.0.0-beta.
|
|
29
|
+
"@phantom/browser-sdk": "^1.0.0-beta.21",
|
|
30
|
+
"@phantom/chain-interfaces": "^1.0.0-beta.9",
|
|
31
|
+
"@phantom/constants": "^1.0.0-beta.9"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@testing-library/dom": "^10.4.0",
|