@phantom/react-native-sdk 1.0.0-beta.1 → 1.0.0-beta.10
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 +44 -40
- package/dist/index.d.ts +15 -36
- package/dist/index.js +49 -189
- package/dist/index.mjs +46 -186
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -89,12 +89,9 @@ export default function App() {
|
|
|
89
89
|
return (
|
|
90
90
|
<PhantomProvider
|
|
91
91
|
config={{
|
|
92
|
-
appId: "your-app-id",
|
|
92
|
+
appId: "your-app-id", // Get your app ID from phantom.com/portal
|
|
93
93
|
scheme: "mywalletapp", // Must match app.json scheme
|
|
94
|
-
embeddedWalletType: "user-wallet",
|
|
95
94
|
addressTypes: [AddressType.solana],
|
|
96
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
97
|
-
solanaProvider: "web3js",
|
|
98
95
|
authOptions: {
|
|
99
96
|
redirectUrl: "mywalletapp://phantom-auth-callback",
|
|
100
97
|
},
|
|
@@ -132,8 +129,10 @@ export function WalletScreen() {
|
|
|
132
129
|
|
|
133
130
|
const handleSignSolanaMessage = async () => {
|
|
134
131
|
try {
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
if (solana.isAvailable) {
|
|
133
|
+
const signature = await solana.solana.signMessage("Hello from Solana!");
|
|
134
|
+
Alert.alert("Solana Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
|
|
135
|
+
}
|
|
137
136
|
} catch (error) {
|
|
138
137
|
Alert.alert("Error", `Failed to sign: ${error.message}`);
|
|
139
138
|
}
|
|
@@ -141,9 +140,11 @@ export function WalletScreen() {
|
|
|
141
140
|
|
|
142
141
|
const handleSignEthereumMessage = async () => {
|
|
143
142
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
if (ethereum.isAvailable) {
|
|
144
|
+
const accounts = await ethereum.ethereum.getAccounts();
|
|
145
|
+
const signature = await ethereum.ethereum.signPersonalMessage("Hello from Ethereum!", accounts[0]);
|
|
146
|
+
Alert.alert("Ethereum Signed!", `Signature: ${signature.slice(0, 10)}...`);
|
|
147
|
+
}
|
|
147
148
|
} catch (error) {
|
|
148
149
|
Alert.alert("Error", `Failed to sign: ${error.message}`);
|
|
149
150
|
}
|
|
@@ -198,15 +199,17 @@ The main provider component that initializes the SDK and provides context to all
|
|
|
198
199
|
```typescript
|
|
199
200
|
interface PhantomSDKConfig {
|
|
200
201
|
scheme: string; // Custom URL scheme for your app
|
|
201
|
-
|
|
202
|
+
appId: string; // Your app ID from phantom.com/portal (required)
|
|
202
203
|
addressTypes: [AddressType, ...AddressType[]]; // e.g., [AddressType.solana]
|
|
203
|
-
|
|
204
|
-
|
|
204
|
+
|
|
205
|
+
// Optional configuration
|
|
206
|
+
embeddedWalletType?: "user-wallet"; // optional, defaults to "user-wallet", currently the only supported type
|
|
207
|
+
apiBaseUrl?: string; // e.g., "https://api.phantom.app/v1/wallets" (optional, has default)
|
|
205
208
|
authOptions?: {
|
|
206
209
|
authUrl?: string; // Custom auth URL (optional)
|
|
207
210
|
redirectUrl?: string; // Custom redirect URL (optional)
|
|
208
211
|
};
|
|
209
|
-
autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (
|
|
212
|
+
autoConnect?: boolean; // Auto-connect to existing session on SDK instantiation (optional, defaults to true)
|
|
210
213
|
}
|
|
211
214
|
```
|
|
212
215
|
|
|
@@ -242,13 +245,18 @@ const {
|
|
|
242
245
|
Provides access to Solana-specific operations.
|
|
243
246
|
|
|
244
247
|
```typescript
|
|
245
|
-
const solana = useSolana();
|
|
248
|
+
const { solana, isAvailable } = useSolana();
|
|
246
249
|
|
|
247
|
-
|
|
248
|
-
|
|
250
|
+
if (isAvailable) {
|
|
251
|
+
// Sign a message
|
|
252
|
+
const signature = await solana.signMessage("Hello Solana!");
|
|
249
253
|
|
|
250
|
-
// Sign
|
|
251
|
-
const
|
|
254
|
+
// Sign a transaction (without sending)
|
|
255
|
+
const signedTx = await solana.signTransaction(transaction);
|
|
256
|
+
|
|
257
|
+
// Sign and send a transaction
|
|
258
|
+
const result = await solana.signAndSendTransaction(transaction);
|
|
259
|
+
}
|
|
252
260
|
```
|
|
253
261
|
|
|
254
262
|
#### useEthereum
|
|
@@ -256,19 +264,24 @@ const result = await solana.signAndSendTransaction(transaction);
|
|
|
256
264
|
Provides access to Ethereum-specific operations.
|
|
257
265
|
|
|
258
266
|
```typescript
|
|
259
|
-
const ethereum = useEthereum();
|
|
267
|
+
const { ethereum, isAvailable } = useEthereum();
|
|
268
|
+
|
|
269
|
+
if (isAvailable) {
|
|
270
|
+
// Get accounts
|
|
271
|
+
const accounts = await ethereum.getAccounts();
|
|
260
272
|
|
|
261
|
-
//
|
|
262
|
-
const
|
|
273
|
+
// Sign a personal message
|
|
274
|
+
const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
|
|
263
275
|
|
|
264
|
-
// Sign a
|
|
265
|
-
const
|
|
276
|
+
// Sign a transaction (without sending)
|
|
277
|
+
const signedTx = await ethereum.signTransaction(transactionData);
|
|
266
278
|
|
|
267
|
-
//
|
|
268
|
-
const result = await ethereum.sendTransaction(transactionData);
|
|
279
|
+
// Sign and send a transaction
|
|
280
|
+
const result = await ethereum.sendTransaction(transactionData);
|
|
269
281
|
|
|
270
|
-
// Get current chain ID
|
|
271
|
-
const chainId = await ethereum.getChainId();
|
|
282
|
+
// Get current chain ID
|
|
283
|
+
const chainId = await ethereum.getChainId();
|
|
284
|
+
}
|
|
272
285
|
```
|
|
273
286
|
|
|
274
287
|
#### useDisconnect
|
|
@@ -330,11 +343,9 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
|
|
|
330
343
|
|
|
331
344
|
<PhantomProvider
|
|
332
345
|
config={{
|
|
333
|
-
appId: "
|
|
346
|
+
appId: "your-app-id",
|
|
334
347
|
scheme: "myapp",
|
|
335
|
-
embeddedWalletType: "user-wallet",
|
|
336
348
|
addressTypes: [AddressType.solana],
|
|
337
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
338
349
|
}}
|
|
339
350
|
>
|
|
340
351
|
<App />
|
|
@@ -348,14 +359,10 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
|
|
|
348
359
|
|
|
349
360
|
<PhantomProvider
|
|
350
361
|
config={{
|
|
351
|
-
appId: "
|
|
362
|
+
appId: "your-app-id",
|
|
352
363
|
scheme: "mycompany-wallet",
|
|
353
|
-
embeddedWalletType: "user-wallet",
|
|
354
364
|
addressTypes: [AddressType.solana, AddressType.ethereum],
|
|
355
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
356
|
-
solanaProvider: "web3js",
|
|
357
365
|
authOptions: {
|
|
358
|
-
authUrl: "https://connect.phantom.app",
|
|
359
366
|
redirectUrl: "mycompany-wallet://auth/success",
|
|
360
367
|
},
|
|
361
368
|
}}
|
|
@@ -389,13 +396,9 @@ import { PhantomProvider, AddressType } from '@phantom/react-native-sdk';
|
|
|
389
396
|
const testConfig = {
|
|
390
397
|
appId: "test-app",
|
|
391
398
|
scheme: "testapp",
|
|
392
|
-
embeddedWalletType: "app-wallet" as const,
|
|
393
399
|
addressTypes: [AddressType.solana],
|
|
394
|
-
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
395
|
-
|
|
396
400
|
};
|
|
397
401
|
|
|
398
|
-
// Use app-wallet for testing (no OAuth required)
|
|
399
402
|
<PhantomProvider config={testConfig}>
|
|
400
403
|
<TestApp />
|
|
401
404
|
</PhantomProvider>
|
|
@@ -420,7 +423,7 @@ adb shell am start -W -a android.intent.action.VIEW -d "myapp://phantom-auth-cal
|
|
|
420
423
|
- Check `app.json` (Expo) or platform-specific configuration
|
|
421
424
|
|
|
422
425
|
2. **"Authentication failed"**
|
|
423
|
-
- Verify your
|
|
426
|
+
- Verify your app ID is correct
|
|
424
427
|
- Check network connectivity
|
|
425
428
|
- Ensure redirect URL matches your scheme
|
|
426
429
|
|
|
@@ -444,6 +447,7 @@ import { PhantomProvider, type PhantomSDKConfig, type PhantomDebugConfig } from
|
|
|
444
447
|
function App() {
|
|
445
448
|
// SDK configuration - static, won't change when debug settings change
|
|
446
449
|
const config: PhantomSDKConfig = {
|
|
450
|
+
appId: "your-app-id",
|
|
447
451
|
scheme: "mywalletapp",
|
|
448
452
|
// ... other config
|
|
449
453
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
|
|
4
4
|
import { EmbeddedProviderConfig, EmbeddedProvider, WalletAddress, ConnectResult } from '@phantom/embedded-provider-core';
|
|
5
5
|
export { ConnectResult, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
|
|
6
|
-
import
|
|
6
|
+
import * as _phantom_chain_interfaces from '@phantom/chain-interfaces';
|
|
7
7
|
export { AddressType } from '@phantom/client';
|
|
8
8
|
export { NetworkId } from '@phantom/constants';
|
|
9
9
|
|
|
@@ -11,11 +11,19 @@ interface PhantomDebugConfig {
|
|
|
11
11
|
/** Enable debug logging */
|
|
12
12
|
enabled?: boolean;
|
|
13
13
|
}
|
|
14
|
-
interface PhantomSDKConfig extends EmbeddedProviderConfig {
|
|
14
|
+
interface PhantomSDKConfig extends Omit<EmbeddedProviderConfig, "apiBaseUrl" | "embeddedWalletType" | "authOptions"> {
|
|
15
15
|
/** Custom URL scheme for your app (e.g., "myapp") */
|
|
16
16
|
scheme: string;
|
|
17
17
|
/** Enable auto-connect to existing sessions (default: true) */
|
|
18
18
|
autoConnect?: boolean;
|
|
19
|
+
/** Base URL for Phantom API (default: "https://api.phantom.app/v1/wallets") */
|
|
20
|
+
apiBaseUrl?: string;
|
|
21
|
+
/** Authentication options */
|
|
22
|
+
embeddedWalletType?: "app-wallet" | "user-wallet";
|
|
23
|
+
authOptions?: {
|
|
24
|
+
authUrl?: string;
|
|
25
|
+
redirectUrl?: string;
|
|
26
|
+
};
|
|
19
27
|
}
|
|
20
28
|
interface ConnectOptions {
|
|
21
29
|
/** OAuth provider to use */
|
|
@@ -27,7 +35,7 @@ interface ConnectOptions {
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
interface PhantomContextValue {
|
|
30
|
-
sdk: EmbeddedProvider
|
|
38
|
+
sdk: EmbeddedProvider;
|
|
31
39
|
isConnected: boolean;
|
|
32
40
|
isConnecting: boolean;
|
|
33
41
|
connectError: Error | null;
|
|
@@ -64,50 +72,21 @@ declare function useAccounts(): {
|
|
|
64
72
|
/**
|
|
65
73
|
* Hook for Solana chain operations in React Native
|
|
66
74
|
*
|
|
67
|
-
* @returns Solana chain interface
|
|
75
|
+
* @returns Solana chain interface with connection enforcement
|
|
68
76
|
*/
|
|
69
77
|
declare function useSolana(): {
|
|
70
|
-
solana: ISolanaChain
|
|
71
|
-
signMessage: (message: string | Uint8Array) => Promise<{
|
|
72
|
-
signature: Uint8Array;
|
|
73
|
-
publicKey: string;
|
|
74
|
-
}>;
|
|
75
|
-
signTransaction: <T>(transaction: T) => Promise<T>;
|
|
76
|
-
signAndSendTransaction: <T>(transaction: T) => Promise<{
|
|
77
|
-
signature: string;
|
|
78
|
-
}>;
|
|
79
|
-
connect: (options?: {
|
|
80
|
-
onlyIfTrusted?: boolean;
|
|
81
|
-
}) => Promise<{
|
|
82
|
-
publicKey: string;
|
|
83
|
-
}>;
|
|
84
|
-
disconnect: () => Promise<void>;
|
|
85
|
-
switchNetwork: (network: "mainnet" | "devnet") => Promise<void | undefined>;
|
|
86
|
-
getPublicKey: () => Promise<string | null>;
|
|
78
|
+
solana: _phantom_chain_interfaces.ISolanaChain;
|
|
87
79
|
isAvailable: boolean;
|
|
88
|
-
isConnected: boolean;
|
|
89
80
|
};
|
|
90
81
|
|
|
91
82
|
/**
|
|
92
83
|
* Hook for Ethereum chain operations in React Native
|
|
93
84
|
*
|
|
94
|
-
* @returns Ethereum chain interface
|
|
85
|
+
* @returns Ethereum chain interface with connection enforcement
|
|
95
86
|
*/
|
|
96
87
|
declare function useEthereum(): {
|
|
97
|
-
ethereum: IEthereumChain
|
|
98
|
-
request: <T = any>(args: {
|
|
99
|
-
method: string;
|
|
100
|
-
params?: unknown[];
|
|
101
|
-
}) => Promise<T>;
|
|
102
|
-
signPersonalMessage: (message: string, address: string) => Promise<string>;
|
|
103
|
-
signMessage: (message: string) => Promise<string>;
|
|
104
|
-
signTypedData: (typedData: any) => Promise<string>;
|
|
105
|
-
sendTransaction: (transaction: EthTransactionRequest) => Promise<string>;
|
|
106
|
-
switchChain: (chainId: number) => Promise<void>;
|
|
107
|
-
getChainId: () => Promise<number>;
|
|
108
|
-
getAccounts: () => Promise<string[]>;
|
|
88
|
+
ethereum: _phantom_chain_interfaces.IEthereumChain;
|
|
109
89
|
isAvailable: boolean;
|
|
110
|
-
isConnected: boolean;
|
|
111
90
|
};
|
|
112
91
|
|
|
113
92
|
export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomSDKConfig, useAccounts, useConnect, useDisconnect, useEthereum, usePhantom, useSolana };
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AddressType: () => import_client.AddressType,
|
|
34
|
-
NetworkId: () =>
|
|
34
|
+
NetworkId: () => import_constants3.NetworkId,
|
|
35
35
|
PhantomProvider: () => PhantomProvider,
|
|
36
36
|
useAccounts: () => useAccounts,
|
|
37
37
|
useConnect: () => useConnect,
|
|
@@ -45,6 +45,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
45
45
|
// src/PhantomProvider.tsx
|
|
46
46
|
var import_react = require("react");
|
|
47
47
|
var import_embedded_provider_core = require("@phantom/embedded-provider-core");
|
|
48
|
+
var import_constants2 = require("@phantom/constants");
|
|
48
49
|
|
|
49
50
|
// src/providers/embedded/storage.ts
|
|
50
51
|
var SecureStore = __toESM(require("expo-secure-store"));
|
|
@@ -96,14 +97,14 @@ var ExpoSecureStorage = class {
|
|
|
96
97
|
|
|
97
98
|
// src/providers/embedded/auth.ts
|
|
98
99
|
var WebBrowser = __toESM(require("expo-web-browser"));
|
|
99
|
-
var
|
|
100
|
+
var import_constants = require("@phantom/constants");
|
|
100
101
|
var ExpoAuthProvider = class {
|
|
101
102
|
async authenticate(options) {
|
|
102
103
|
if ("jwtToken" in options) {
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
105
106
|
const phantomOptions = options;
|
|
106
|
-
const { authUrl, redirectUrl, organizationId,
|
|
107
|
+
const { authUrl, redirectUrl, organizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
|
|
107
108
|
if (!redirectUrl) {
|
|
108
109
|
throw new Error("redirectUrl is required for web browser authentication");
|
|
109
110
|
}
|
|
@@ -111,14 +112,14 @@ var ExpoAuthProvider = class {
|
|
|
111
112
|
throw new Error("organizationId, sessionId and appId are required for authentication");
|
|
112
113
|
}
|
|
113
114
|
try {
|
|
114
|
-
const baseUrl = authUrl || DEFAULT_AUTH_URL;
|
|
115
|
+
const baseUrl = authUrl || import_constants.DEFAULT_AUTH_URL;
|
|
115
116
|
const params = new URLSearchParams({
|
|
116
117
|
organization_id: organizationId,
|
|
117
|
-
parent_organization_id: parentOrganizationId,
|
|
118
118
|
app_id: appId,
|
|
119
119
|
redirect_uri: redirectUrl,
|
|
120
120
|
session_id: sessionId,
|
|
121
|
-
clear_previous_session: "true"
|
|
121
|
+
clear_previous_session: "true",
|
|
122
|
+
sdk_version: "1.0.0-beta.10"
|
|
122
123
|
});
|
|
123
124
|
if (provider) {
|
|
124
125
|
console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
|
|
@@ -136,7 +137,6 @@ var ExpoAuthProvider = class {
|
|
|
136
137
|
baseUrl,
|
|
137
138
|
redirectUrl,
|
|
138
139
|
organizationId,
|
|
139
|
-
parentOrganizationId,
|
|
140
140
|
sessionId,
|
|
141
141
|
provider,
|
|
142
142
|
hasCustomData: !!customAuthData
|
|
@@ -262,7 +262,7 @@ var ReactNativeStamper = class {
|
|
|
262
262
|
this.algorithm = import_sdk_types.Algorithm.ed25519;
|
|
263
263
|
this.type = "PKI";
|
|
264
264
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
265
|
-
this.
|
|
265
|
+
this.appId = config.appId || "default";
|
|
266
266
|
}
|
|
267
267
|
/**
|
|
268
268
|
* Initialize the stamper and generate/load cryptographic keys
|
|
@@ -415,10 +415,10 @@ var ReactNativeStamper = class {
|
|
|
415
415
|
return null;
|
|
416
416
|
}
|
|
417
417
|
getActiveKeyName() {
|
|
418
|
-
return `${this.keyPrefix}-${this.
|
|
418
|
+
return `${this.keyPrefix}-${this.appId}-active`;
|
|
419
419
|
}
|
|
420
420
|
getPendingKeyName() {
|
|
421
|
-
return `${this.keyPrefix}-${this.
|
|
421
|
+
return `${this.keyPrefix}-${this.appId}-pending`;
|
|
422
422
|
}
|
|
423
423
|
};
|
|
424
424
|
|
|
@@ -459,34 +459,48 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
459
459
|
const [connectError, setConnectError] = (0, import_react.useState)(null);
|
|
460
460
|
const [addresses, setAddresses] = (0, import_react.useState)([]);
|
|
461
461
|
const [walletId, setWalletId] = (0, import_react.useState)(null);
|
|
462
|
-
const [sdk, setSdk] = (0, import_react.useState)(null);
|
|
463
462
|
const memoizedConfig = (0, import_react.useMemo)(() => {
|
|
464
463
|
const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
|
|
465
464
|
return {
|
|
466
465
|
...config,
|
|
466
|
+
apiBaseUrl: config.apiBaseUrl || import_constants2.DEFAULT_WALLET_API_URL,
|
|
467
|
+
embeddedWalletType: config.embeddedWalletType || import_constants2.DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
467
468
|
authOptions: {
|
|
468
469
|
...config.authOptions || {},
|
|
469
|
-
redirectUrl
|
|
470
|
+
redirectUrl,
|
|
471
|
+
authUrl: config.authOptions?.authUrl || import_constants2.DEFAULT_AUTH_URL
|
|
470
472
|
}
|
|
471
473
|
};
|
|
472
474
|
}, [config]);
|
|
473
|
-
(0, import_react.
|
|
475
|
+
const sdk = (0, import_react.useMemo)(() => {
|
|
474
476
|
const storage = new ExpoSecureStorage();
|
|
475
477
|
const authProvider = new ExpoAuthProvider();
|
|
476
478
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
477
479
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
478
480
|
const stamper = new ReactNativeStamper({
|
|
479
|
-
keyPrefix: `phantom-rn-${memoizedConfig.
|
|
480
|
-
|
|
481
|
+
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
482
|
+
appId: memoizedConfig.appId
|
|
481
483
|
});
|
|
484
|
+
const platformName = `${import_react_native2.Platform.OS}-${import_react_native2.Platform.Version}`;
|
|
482
485
|
const platform = {
|
|
483
486
|
storage,
|
|
484
487
|
authProvider,
|
|
485
488
|
urlParamsAccessor,
|
|
486
489
|
stamper,
|
|
487
|
-
name:
|
|
490
|
+
name: platformName,
|
|
491
|
+
analyticsHeaders: {
|
|
492
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
493
|
+
[import_constants2.ANALYTICS_HEADERS.PLATFORM]: import_react_native2.Platform.OS,
|
|
494
|
+
[import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native2.Platform.Version}`,
|
|
495
|
+
[import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
496
|
+
[import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
497
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.10"
|
|
498
|
+
// Replaced at build time
|
|
499
|
+
}
|
|
488
500
|
};
|
|
489
|
-
|
|
501
|
+
return new import_embedded_provider_core.EmbeddedProvider(memoizedConfig, platform, logger);
|
|
502
|
+
}, [memoizedConfig, debugConfig, config.appId, config.embeddedWalletType]);
|
|
503
|
+
(0, import_react.useEffect)(() => {
|
|
490
504
|
const handleConnectStart = () => {
|
|
491
505
|
setIsConnecting(true);
|
|
492
506
|
setConnectError(null);
|
|
@@ -495,12 +509,12 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
495
509
|
try {
|
|
496
510
|
setIsConnected(true);
|
|
497
511
|
setIsConnecting(false);
|
|
498
|
-
const addrs = await
|
|
512
|
+
const addrs = await sdk.getAddresses();
|
|
499
513
|
setAddresses(addrs);
|
|
500
514
|
} catch (err) {
|
|
501
515
|
console.error("Error connecting:", err);
|
|
502
516
|
try {
|
|
503
|
-
await
|
|
517
|
+
await sdk.disconnect();
|
|
504
518
|
} catch (err2) {
|
|
505
519
|
console.error("Error disconnecting:", err2);
|
|
506
520
|
}
|
|
@@ -517,21 +531,18 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
517
531
|
setAddresses([]);
|
|
518
532
|
setWalletId(null);
|
|
519
533
|
};
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
setSdk(sdkInstance);
|
|
534
|
+
sdk.on("connect_start", handleConnectStart);
|
|
535
|
+
sdk.on("connect", handleConnect);
|
|
536
|
+
sdk.on("connect_error", handleConnectError);
|
|
537
|
+
sdk.on("disconnect", handleDisconnect);
|
|
525
538
|
return () => {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
539
|
+
sdk.off("connect_start", handleConnectStart);
|
|
540
|
+
sdk.off("connect", handleConnect);
|
|
541
|
+
sdk.off("connect_error", handleConnectError);
|
|
542
|
+
sdk.off("disconnect", handleDisconnect);
|
|
530
543
|
};
|
|
531
|
-
}, [
|
|
544
|
+
}, [sdk]);
|
|
532
545
|
(0, import_react.useEffect)(() => {
|
|
533
|
-
if (!sdk)
|
|
534
|
-
return;
|
|
535
546
|
if (config.autoConnect !== false) {
|
|
536
547
|
sdk.autoConnect().catch(() => {
|
|
537
548
|
});
|
|
@@ -628,181 +639,30 @@ function useAccounts() {
|
|
|
628
639
|
}
|
|
629
640
|
|
|
630
641
|
// src/hooks/useSolana.ts
|
|
631
|
-
var import_react4 = require("react");
|
|
632
642
|
function useSolana() {
|
|
633
643
|
const { sdk, isConnected } = usePhantom();
|
|
634
|
-
const solanaChain = (0, import_react4.useMemo)(() => {
|
|
635
|
-
if (!sdk || !isConnected)
|
|
636
|
-
return null;
|
|
637
|
-
try {
|
|
638
|
-
return sdk.solana;
|
|
639
|
-
} catch {
|
|
640
|
-
return null;
|
|
641
|
-
}
|
|
642
|
-
}, [sdk, isConnected]);
|
|
643
|
-
const signMessage = (0, import_react4.useCallback)(
|
|
644
|
-
async (message) => {
|
|
645
|
-
if (!solanaChain)
|
|
646
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
647
|
-
return await solanaChain.signMessage(message);
|
|
648
|
-
},
|
|
649
|
-
[solanaChain]
|
|
650
|
-
);
|
|
651
|
-
const signTransaction = (0, import_react4.useCallback)(
|
|
652
|
-
async (transaction) => {
|
|
653
|
-
if (!solanaChain)
|
|
654
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
655
|
-
return await solanaChain.signTransaction(transaction);
|
|
656
|
-
},
|
|
657
|
-
[solanaChain]
|
|
658
|
-
);
|
|
659
|
-
const signAndSendTransaction = (0, import_react4.useCallback)(
|
|
660
|
-
async (transaction) => {
|
|
661
|
-
if (!solanaChain)
|
|
662
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
663
|
-
return await solanaChain.signAndSendTransaction(transaction);
|
|
664
|
-
},
|
|
665
|
-
[solanaChain]
|
|
666
|
-
);
|
|
667
|
-
const connect = (0, import_react4.useCallback)(
|
|
668
|
-
async (options) => {
|
|
669
|
-
if (!solanaChain)
|
|
670
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
671
|
-
return await solanaChain.connect(options);
|
|
672
|
-
},
|
|
673
|
-
[solanaChain]
|
|
674
|
-
);
|
|
675
|
-
const disconnect = (0, import_react4.useCallback)(async () => {
|
|
676
|
-
if (!solanaChain)
|
|
677
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
678
|
-
return await solanaChain.disconnect();
|
|
679
|
-
}, [solanaChain]);
|
|
680
|
-
const switchNetwork = (0, import_react4.useCallback)(
|
|
681
|
-
async (network) => {
|
|
682
|
-
if (!solanaChain)
|
|
683
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
684
|
-
return await solanaChain.switchNetwork?.(network);
|
|
685
|
-
},
|
|
686
|
-
[solanaChain]
|
|
687
|
-
);
|
|
688
|
-
const getPublicKey = (0, import_react4.useCallback)(async () => {
|
|
689
|
-
if (!solanaChain)
|
|
690
|
-
return null;
|
|
691
|
-
return await solanaChain.getPublicKey();
|
|
692
|
-
}, [solanaChain]);
|
|
693
644
|
return {
|
|
694
|
-
// Chain instance for
|
|
695
|
-
solana:
|
|
696
|
-
// Convenient methods
|
|
697
|
-
signMessage,
|
|
698
|
-
signTransaction,
|
|
699
|
-
signAndSendTransaction,
|
|
700
|
-
connect,
|
|
701
|
-
disconnect,
|
|
702
|
-
switchNetwork,
|
|
703
|
-
getPublicKey,
|
|
645
|
+
// Chain instance with connection enforcement for signing methods
|
|
646
|
+
solana: sdk.solana,
|
|
704
647
|
// State
|
|
705
|
-
isAvailable: !!
|
|
706
|
-
isConnected: solanaChain?.isConnected() ?? false
|
|
648
|
+
isAvailable: !!isConnected
|
|
707
649
|
};
|
|
708
650
|
}
|
|
709
651
|
|
|
710
652
|
// src/hooks/useEthereum.ts
|
|
711
|
-
var import_react5 = require("react");
|
|
712
653
|
function useEthereum() {
|
|
713
654
|
const { sdk, isConnected } = usePhantom();
|
|
714
|
-
const ethereumChain = (0, import_react5.useMemo)(() => {
|
|
715
|
-
if (!sdk || !isConnected)
|
|
716
|
-
return null;
|
|
717
|
-
try {
|
|
718
|
-
return sdk.ethereum;
|
|
719
|
-
} catch {
|
|
720
|
-
return null;
|
|
721
|
-
}
|
|
722
|
-
}, [sdk, isConnected]);
|
|
723
|
-
const request = (0, import_react5.useCallback)(
|
|
724
|
-
async (args) => {
|
|
725
|
-
if (!ethereumChain)
|
|
726
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
727
|
-
return await ethereumChain.request(args);
|
|
728
|
-
},
|
|
729
|
-
[ethereumChain]
|
|
730
|
-
);
|
|
731
|
-
const signPersonalMessage = (0, import_react5.useCallback)(
|
|
732
|
-
async (message, address) => {
|
|
733
|
-
if (!ethereumChain)
|
|
734
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
735
|
-
return await ethereumChain.signPersonalMessage(message, address);
|
|
736
|
-
},
|
|
737
|
-
[ethereumChain]
|
|
738
|
-
);
|
|
739
|
-
const sendTransaction = (0, import_react5.useCallback)(
|
|
740
|
-
async (transaction) => {
|
|
741
|
-
if (!ethereumChain)
|
|
742
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
743
|
-
return await ethereumChain.sendTransaction(transaction);
|
|
744
|
-
},
|
|
745
|
-
[ethereumChain]
|
|
746
|
-
);
|
|
747
|
-
const switchChain = (0, import_react5.useCallback)(
|
|
748
|
-
async (chainId) => {
|
|
749
|
-
if (!ethereumChain)
|
|
750
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
751
|
-
return await ethereumChain.switchChain(chainId);
|
|
752
|
-
},
|
|
753
|
-
[ethereumChain]
|
|
754
|
-
);
|
|
755
|
-
const getChainId = (0, import_react5.useCallback)(async () => {
|
|
756
|
-
if (!ethereumChain)
|
|
757
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
758
|
-
return await ethereumChain.getChainId();
|
|
759
|
-
}, [ethereumChain]);
|
|
760
|
-
const getAccounts = (0, import_react5.useCallback)(async () => {
|
|
761
|
-
if (!ethereumChain)
|
|
762
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
763
|
-
return await ethereumChain.getAccounts();
|
|
764
|
-
}, [ethereumChain]);
|
|
765
|
-
const signMessage = (0, import_react5.useCallback)(
|
|
766
|
-
async (message) => {
|
|
767
|
-
const accounts = await getAccounts();
|
|
768
|
-
return await request({
|
|
769
|
-
method: "eth_sign",
|
|
770
|
-
params: [accounts[0], message]
|
|
771
|
-
});
|
|
772
|
-
},
|
|
773
|
-
[request, getAccounts]
|
|
774
|
-
);
|
|
775
|
-
const signTypedData = (0, import_react5.useCallback)(
|
|
776
|
-
async (typedData) => {
|
|
777
|
-
if (!ethereumChain)
|
|
778
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
779
|
-
const accounts = await getAccounts();
|
|
780
|
-
return await ethereumChain.signTypedData(typedData, accounts[0]);
|
|
781
|
-
},
|
|
782
|
-
[ethereumChain, getAccounts]
|
|
783
|
-
);
|
|
784
655
|
return {
|
|
785
|
-
// Chain instance for
|
|
786
|
-
ethereum:
|
|
787
|
-
// Standard EIP-1193 interface
|
|
788
|
-
request,
|
|
789
|
-
// Convenient methods
|
|
790
|
-
signPersonalMessage,
|
|
791
|
-
signMessage,
|
|
792
|
-
signTypedData,
|
|
793
|
-
sendTransaction,
|
|
794
|
-
switchChain,
|
|
795
|
-
getChainId,
|
|
796
|
-
getAccounts,
|
|
656
|
+
// Chain instance with connection enforcement for signing methods
|
|
657
|
+
ethereum: sdk.ethereum,
|
|
797
658
|
// State
|
|
798
|
-
isAvailable: !!
|
|
799
|
-
isConnected: ethereumChain?.isConnected() ?? false
|
|
659
|
+
isAvailable: !!isConnected
|
|
800
660
|
};
|
|
801
661
|
}
|
|
802
662
|
|
|
803
663
|
// src/index.ts
|
|
804
664
|
var import_client = require("@phantom/client");
|
|
805
|
-
var
|
|
665
|
+
var import_constants3 = require("@phantom/constants");
|
|
806
666
|
// Annotate the CommonJS export names for ESM import in node:
|
|
807
667
|
0 && (module.exports = {
|
|
808
668
|
AddressType,
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/PhantomProvider.tsx
|
|
2
2
|
import { createContext, useContext, useState, useEffect, useMemo } from "react";
|
|
3
3
|
import { EmbeddedProvider } from "@phantom/embedded-provider-core";
|
|
4
|
+
import { ANALYTICS_HEADERS, DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
|
|
4
5
|
|
|
5
6
|
// src/providers/embedded/storage.ts
|
|
6
7
|
import * as SecureStore from "expo-secure-store";
|
|
@@ -52,14 +53,14 @@ var ExpoSecureStorage = class {
|
|
|
52
53
|
|
|
53
54
|
// src/providers/embedded/auth.ts
|
|
54
55
|
import * as WebBrowser from "expo-web-browser";
|
|
55
|
-
|
|
56
|
+
import { DEFAULT_AUTH_URL } from "@phantom/constants";
|
|
56
57
|
var ExpoAuthProvider = class {
|
|
57
58
|
async authenticate(options) {
|
|
58
59
|
if ("jwtToken" in options) {
|
|
59
60
|
return;
|
|
60
61
|
}
|
|
61
62
|
const phantomOptions = options;
|
|
62
|
-
const { authUrl, redirectUrl, organizationId,
|
|
63
|
+
const { authUrl, redirectUrl, organizationId, sessionId, provider, customAuthData, appId } = phantomOptions;
|
|
63
64
|
if (!redirectUrl) {
|
|
64
65
|
throw new Error("redirectUrl is required for web browser authentication");
|
|
65
66
|
}
|
|
@@ -70,11 +71,11 @@ var ExpoAuthProvider = class {
|
|
|
70
71
|
const baseUrl = authUrl || DEFAULT_AUTH_URL;
|
|
71
72
|
const params = new URLSearchParams({
|
|
72
73
|
organization_id: organizationId,
|
|
73
|
-
parent_organization_id: parentOrganizationId,
|
|
74
74
|
app_id: appId,
|
|
75
75
|
redirect_uri: redirectUrl,
|
|
76
76
|
session_id: sessionId,
|
|
77
|
-
clear_previous_session: "true"
|
|
77
|
+
clear_previous_session: "true",
|
|
78
|
+
sdk_version: "1.0.0-beta.10"
|
|
78
79
|
});
|
|
79
80
|
if (provider) {
|
|
80
81
|
console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
|
|
@@ -92,7 +93,6 @@ var ExpoAuthProvider = class {
|
|
|
92
93
|
baseUrl,
|
|
93
94
|
redirectUrl,
|
|
94
95
|
organizationId,
|
|
95
|
-
parentOrganizationId,
|
|
96
96
|
sessionId,
|
|
97
97
|
provider,
|
|
98
98
|
hasCustomData: !!customAuthData
|
|
@@ -218,7 +218,7 @@ var ReactNativeStamper = class {
|
|
|
218
218
|
this.algorithm = Algorithm.ed25519;
|
|
219
219
|
this.type = "PKI";
|
|
220
220
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
221
|
-
this.
|
|
221
|
+
this.appId = config.appId || "default";
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
224
|
* Initialize the stamper and generate/load cryptographic keys
|
|
@@ -371,10 +371,10 @@ var ReactNativeStamper = class {
|
|
|
371
371
|
return null;
|
|
372
372
|
}
|
|
373
373
|
getActiveKeyName() {
|
|
374
|
-
return `${this.keyPrefix}-${this.
|
|
374
|
+
return `${this.keyPrefix}-${this.appId}-active`;
|
|
375
375
|
}
|
|
376
376
|
getPendingKeyName() {
|
|
377
|
-
return `${this.keyPrefix}-${this.
|
|
377
|
+
return `${this.keyPrefix}-${this.appId}-pending`;
|
|
378
378
|
}
|
|
379
379
|
};
|
|
380
380
|
|
|
@@ -415,34 +415,48 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
415
415
|
const [connectError, setConnectError] = useState(null);
|
|
416
416
|
const [addresses, setAddresses] = useState([]);
|
|
417
417
|
const [walletId, setWalletId] = useState(null);
|
|
418
|
-
const [sdk, setSdk] = useState(null);
|
|
419
418
|
const memoizedConfig = useMemo(() => {
|
|
420
419
|
const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
|
|
421
420
|
return {
|
|
422
421
|
...config,
|
|
422
|
+
apiBaseUrl: config.apiBaseUrl || DEFAULT_WALLET_API_URL,
|
|
423
|
+
embeddedWalletType: config.embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
423
424
|
authOptions: {
|
|
424
425
|
...config.authOptions || {},
|
|
425
|
-
redirectUrl
|
|
426
|
+
redirectUrl,
|
|
427
|
+
authUrl: config.authOptions?.authUrl || DEFAULT_AUTH_URL2
|
|
426
428
|
}
|
|
427
429
|
};
|
|
428
430
|
}, [config]);
|
|
429
|
-
|
|
431
|
+
const sdk = useMemo(() => {
|
|
430
432
|
const storage = new ExpoSecureStorage();
|
|
431
433
|
const authProvider = new ExpoAuthProvider();
|
|
432
434
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
433
435
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
434
436
|
const stamper = new ReactNativeStamper({
|
|
435
|
-
keyPrefix: `phantom-rn-${memoizedConfig.
|
|
436
|
-
|
|
437
|
+
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
438
|
+
appId: memoizedConfig.appId
|
|
437
439
|
});
|
|
440
|
+
const platformName = `${Platform.OS}-${Platform.Version}`;
|
|
438
441
|
const platform = {
|
|
439
442
|
storage,
|
|
440
443
|
authProvider,
|
|
441
444
|
urlParamsAccessor,
|
|
442
445
|
stamper,
|
|
443
|
-
name:
|
|
446
|
+
name: platformName,
|
|
447
|
+
analyticsHeaders: {
|
|
448
|
+
[ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
449
|
+
[ANALYTICS_HEADERS.PLATFORM]: Platform.OS,
|
|
450
|
+
[ANALYTICS_HEADERS.PLATFORM_VERSION]: `${Platform.Version}`,
|
|
451
|
+
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
452
|
+
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
453
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.10"
|
|
454
|
+
// Replaced at build time
|
|
455
|
+
}
|
|
444
456
|
};
|
|
445
|
-
|
|
457
|
+
return new EmbeddedProvider(memoizedConfig, platform, logger);
|
|
458
|
+
}, [memoizedConfig, debugConfig, config.appId, config.embeddedWalletType]);
|
|
459
|
+
useEffect(() => {
|
|
446
460
|
const handleConnectStart = () => {
|
|
447
461
|
setIsConnecting(true);
|
|
448
462
|
setConnectError(null);
|
|
@@ -451,12 +465,12 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
451
465
|
try {
|
|
452
466
|
setIsConnected(true);
|
|
453
467
|
setIsConnecting(false);
|
|
454
|
-
const addrs = await
|
|
468
|
+
const addrs = await sdk.getAddresses();
|
|
455
469
|
setAddresses(addrs);
|
|
456
470
|
} catch (err) {
|
|
457
471
|
console.error("Error connecting:", err);
|
|
458
472
|
try {
|
|
459
|
-
await
|
|
473
|
+
await sdk.disconnect();
|
|
460
474
|
} catch (err2) {
|
|
461
475
|
console.error("Error disconnecting:", err2);
|
|
462
476
|
}
|
|
@@ -473,21 +487,18 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
473
487
|
setAddresses([]);
|
|
474
488
|
setWalletId(null);
|
|
475
489
|
};
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
setSdk(sdkInstance);
|
|
490
|
+
sdk.on("connect_start", handleConnectStart);
|
|
491
|
+
sdk.on("connect", handleConnect);
|
|
492
|
+
sdk.on("connect_error", handleConnectError);
|
|
493
|
+
sdk.on("disconnect", handleDisconnect);
|
|
481
494
|
return () => {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
495
|
+
sdk.off("connect_start", handleConnectStart);
|
|
496
|
+
sdk.off("connect", handleConnect);
|
|
497
|
+
sdk.off("connect_error", handleConnectError);
|
|
498
|
+
sdk.off("disconnect", handleDisconnect);
|
|
486
499
|
};
|
|
487
|
-
}, [
|
|
500
|
+
}, [sdk]);
|
|
488
501
|
useEffect(() => {
|
|
489
|
-
if (!sdk)
|
|
490
|
-
return;
|
|
491
502
|
if (config.autoConnect !== false) {
|
|
492
503
|
sdk.autoConnect().catch(() => {
|
|
493
504
|
});
|
|
@@ -584,175 +595,24 @@ function useAccounts() {
|
|
|
584
595
|
}
|
|
585
596
|
|
|
586
597
|
// src/hooks/useSolana.ts
|
|
587
|
-
import { useCallback as useCallback3, useMemo as useMemo2 } from "react";
|
|
588
598
|
function useSolana() {
|
|
589
599
|
const { sdk, isConnected } = usePhantom();
|
|
590
|
-
const solanaChain = useMemo2(() => {
|
|
591
|
-
if (!sdk || !isConnected)
|
|
592
|
-
return null;
|
|
593
|
-
try {
|
|
594
|
-
return sdk.solana;
|
|
595
|
-
} catch {
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
}, [sdk, isConnected]);
|
|
599
|
-
const signMessage = useCallback3(
|
|
600
|
-
async (message) => {
|
|
601
|
-
if (!solanaChain)
|
|
602
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
603
|
-
return await solanaChain.signMessage(message);
|
|
604
|
-
},
|
|
605
|
-
[solanaChain]
|
|
606
|
-
);
|
|
607
|
-
const signTransaction = useCallback3(
|
|
608
|
-
async (transaction) => {
|
|
609
|
-
if (!solanaChain)
|
|
610
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
611
|
-
return await solanaChain.signTransaction(transaction);
|
|
612
|
-
},
|
|
613
|
-
[solanaChain]
|
|
614
|
-
);
|
|
615
|
-
const signAndSendTransaction = useCallback3(
|
|
616
|
-
async (transaction) => {
|
|
617
|
-
if (!solanaChain)
|
|
618
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
619
|
-
return await solanaChain.signAndSendTransaction(transaction);
|
|
620
|
-
},
|
|
621
|
-
[solanaChain]
|
|
622
|
-
);
|
|
623
|
-
const connect = useCallback3(
|
|
624
|
-
async (options) => {
|
|
625
|
-
if (!solanaChain)
|
|
626
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
627
|
-
return await solanaChain.connect(options);
|
|
628
|
-
},
|
|
629
|
-
[solanaChain]
|
|
630
|
-
);
|
|
631
|
-
const disconnect = useCallback3(async () => {
|
|
632
|
-
if (!solanaChain)
|
|
633
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
634
|
-
return await solanaChain.disconnect();
|
|
635
|
-
}, [solanaChain]);
|
|
636
|
-
const switchNetwork = useCallback3(
|
|
637
|
-
async (network) => {
|
|
638
|
-
if (!solanaChain)
|
|
639
|
-
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
640
|
-
return await solanaChain.switchNetwork?.(network);
|
|
641
|
-
},
|
|
642
|
-
[solanaChain]
|
|
643
|
-
);
|
|
644
|
-
const getPublicKey = useCallback3(async () => {
|
|
645
|
-
if (!solanaChain)
|
|
646
|
-
return null;
|
|
647
|
-
return await solanaChain.getPublicKey();
|
|
648
|
-
}, [solanaChain]);
|
|
649
600
|
return {
|
|
650
|
-
// Chain instance for
|
|
651
|
-
solana:
|
|
652
|
-
// Convenient methods
|
|
653
|
-
signMessage,
|
|
654
|
-
signTransaction,
|
|
655
|
-
signAndSendTransaction,
|
|
656
|
-
connect,
|
|
657
|
-
disconnect,
|
|
658
|
-
switchNetwork,
|
|
659
|
-
getPublicKey,
|
|
601
|
+
// Chain instance with connection enforcement for signing methods
|
|
602
|
+
solana: sdk.solana,
|
|
660
603
|
// State
|
|
661
|
-
isAvailable: !!
|
|
662
|
-
isConnected: solanaChain?.isConnected() ?? false
|
|
604
|
+
isAvailable: !!isConnected
|
|
663
605
|
};
|
|
664
606
|
}
|
|
665
607
|
|
|
666
608
|
// src/hooks/useEthereum.ts
|
|
667
|
-
import { useCallback as useCallback4, useMemo as useMemo3 } from "react";
|
|
668
609
|
function useEthereum() {
|
|
669
610
|
const { sdk, isConnected } = usePhantom();
|
|
670
|
-
const ethereumChain = useMemo3(() => {
|
|
671
|
-
if (!sdk || !isConnected)
|
|
672
|
-
return null;
|
|
673
|
-
try {
|
|
674
|
-
return sdk.ethereum;
|
|
675
|
-
} catch {
|
|
676
|
-
return null;
|
|
677
|
-
}
|
|
678
|
-
}, [sdk, isConnected]);
|
|
679
|
-
const request = useCallback4(
|
|
680
|
-
async (args) => {
|
|
681
|
-
if (!ethereumChain)
|
|
682
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
683
|
-
return await ethereumChain.request(args);
|
|
684
|
-
},
|
|
685
|
-
[ethereumChain]
|
|
686
|
-
);
|
|
687
|
-
const signPersonalMessage = useCallback4(
|
|
688
|
-
async (message, address) => {
|
|
689
|
-
if (!ethereumChain)
|
|
690
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
691
|
-
return await ethereumChain.signPersonalMessage(message, address);
|
|
692
|
-
},
|
|
693
|
-
[ethereumChain]
|
|
694
|
-
);
|
|
695
|
-
const sendTransaction = useCallback4(
|
|
696
|
-
async (transaction) => {
|
|
697
|
-
if (!ethereumChain)
|
|
698
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
699
|
-
return await ethereumChain.sendTransaction(transaction);
|
|
700
|
-
},
|
|
701
|
-
[ethereumChain]
|
|
702
|
-
);
|
|
703
|
-
const switchChain = useCallback4(
|
|
704
|
-
async (chainId) => {
|
|
705
|
-
if (!ethereumChain)
|
|
706
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
707
|
-
return await ethereumChain.switchChain(chainId);
|
|
708
|
-
},
|
|
709
|
-
[ethereumChain]
|
|
710
|
-
);
|
|
711
|
-
const getChainId = useCallback4(async () => {
|
|
712
|
-
if (!ethereumChain)
|
|
713
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
714
|
-
return await ethereumChain.getChainId();
|
|
715
|
-
}, [ethereumChain]);
|
|
716
|
-
const getAccounts = useCallback4(async () => {
|
|
717
|
-
if (!ethereumChain)
|
|
718
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
719
|
-
return await ethereumChain.getAccounts();
|
|
720
|
-
}, [ethereumChain]);
|
|
721
|
-
const signMessage = useCallback4(
|
|
722
|
-
async (message) => {
|
|
723
|
-
const accounts = await getAccounts();
|
|
724
|
-
return await request({
|
|
725
|
-
method: "eth_sign",
|
|
726
|
-
params: [accounts[0], message]
|
|
727
|
-
});
|
|
728
|
-
},
|
|
729
|
-
[request, getAccounts]
|
|
730
|
-
);
|
|
731
|
-
const signTypedData = useCallback4(
|
|
732
|
-
async (typedData) => {
|
|
733
|
-
if (!ethereumChain)
|
|
734
|
-
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
735
|
-
const accounts = await getAccounts();
|
|
736
|
-
return await ethereumChain.signTypedData(typedData, accounts[0]);
|
|
737
|
-
},
|
|
738
|
-
[ethereumChain, getAccounts]
|
|
739
|
-
);
|
|
740
611
|
return {
|
|
741
|
-
// Chain instance for
|
|
742
|
-
ethereum:
|
|
743
|
-
// Standard EIP-1193 interface
|
|
744
|
-
request,
|
|
745
|
-
// Convenient methods
|
|
746
|
-
signPersonalMessage,
|
|
747
|
-
signMessage,
|
|
748
|
-
signTypedData,
|
|
749
|
-
sendTransaction,
|
|
750
|
-
switchChain,
|
|
751
|
-
getChainId,
|
|
752
|
-
getAccounts,
|
|
612
|
+
// Chain instance with connection enforcement for signing methods
|
|
613
|
+
ethereum: sdk.ethereum,
|
|
753
614
|
// State
|
|
754
|
-
isAvailable: !!
|
|
755
|
-
isConnected: ethereumChain?.isConnected() ?? false
|
|
615
|
+
isAvailable: !!isConnected
|
|
756
616
|
};
|
|
757
617
|
}
|
|
758
618
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/react-native-sdk",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.10",
|
|
4
4
|
"description": "Phantom Wallet SDK for React Native and Expo applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -45,14 +45,14 @@
|
|
|
45
45
|
"directory": "packages/react-native-sdk"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@phantom/api-key-stamper": "^1.0.0-beta.
|
|
49
|
-
"@phantom/base64url": "^1.0.0-beta.
|
|
50
|
-
"@phantom/
|
|
51
|
-
"@phantom/client": "^1.0.0-beta.
|
|
52
|
-
"@phantom/constants": "^1.0.0-beta.
|
|
53
|
-
"@phantom/crypto": "^1.0.0-beta.
|
|
54
|
-
"@phantom/embedded-provider-core": "^1.0.0-beta.
|
|
55
|
-
"@phantom/sdk-types": "^1.0.0-beta.
|
|
48
|
+
"@phantom/api-key-stamper": "^1.0.0-beta.6",
|
|
49
|
+
"@phantom/base64url": "^1.0.0-beta.6",
|
|
50
|
+
"@phantom/chain-interfaces": "^1.0.0-beta.6",
|
|
51
|
+
"@phantom/client": "^1.0.0-beta.10",
|
|
52
|
+
"@phantom/constants": "^1.0.0-beta.6",
|
|
53
|
+
"@phantom/crypto": "^1.0.0-beta.6",
|
|
54
|
+
"@phantom/embedded-provider-core": "^1.0.0-beta.10",
|
|
55
|
+
"@phantom/sdk-types": "^1.0.0-beta.6",
|
|
56
56
|
"@types/bs58": "^5.0.0",
|
|
57
57
|
"bs58": "^6.0.0",
|
|
58
58
|
"buffer": "^6.0.3"
|