@phantom/react-native-sdk 1.0.0-beta.1 → 1.0.0-beta.11
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 +46 -42
- package/dist/index.d.ts +15 -36
- package/dist/index.js +69 -194
- package/dist/index.mjs +66 -191
- 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
|
},
|
|
@@ -117,8 +114,8 @@ import { useConnect, useAccounts, useSolana, useEthereum, useDisconnect } from "
|
|
|
117
114
|
export function WalletScreen() {
|
|
118
115
|
const { connect, isConnecting, error: connectError } = useConnect();
|
|
119
116
|
const { addresses, isConnected } = useAccounts();
|
|
120
|
-
const solana = useSolana();
|
|
121
|
-
const ethereum = useEthereum();
|
|
117
|
+
const { solana } = useSolana();
|
|
118
|
+
const { ethereum } = useEthereum();
|
|
122
119
|
const { disconnect } = useDisconnect();
|
|
123
120
|
|
|
124
121
|
const handleConnect = async () => {
|
|
@@ -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 { ISolanaChain, IEthereumChain
|
|
6
|
+
import { ISolanaChain, IEthereumChain } 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: 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: 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,29 +97,29 @@ 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,
|
|
107
|
+
const { authUrl, redirectUrl, publicKey, sessionId, provider, customAuthData, appId } = phantomOptions;
|
|
107
108
|
if (!redirectUrl) {
|
|
108
109
|
throw new Error("redirectUrl is required for web browser authentication");
|
|
109
110
|
}
|
|
110
|
-
if (!
|
|
111
|
-
throw new Error("
|
|
111
|
+
if (!publicKey || !sessionId || !appId) {
|
|
112
|
+
throw new Error("publicKey, 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
|
-
parent_organization_id: parentOrganizationId,
|
|
117
|
+
public_key: publicKey,
|
|
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.11"
|
|
122
123
|
});
|
|
123
124
|
if (provider) {
|
|
124
125
|
console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
|
|
@@ -135,8 +136,7 @@ var ExpoAuthProvider = class {
|
|
|
135
136
|
console.log("[ExpoAuthProvider] Starting authentication", {
|
|
136
137
|
baseUrl,
|
|
137
138
|
redirectUrl,
|
|
138
|
-
|
|
139
|
-
parentOrganizationId,
|
|
139
|
+
publicKey,
|
|
140
140
|
sessionId,
|
|
141
141
|
provider,
|
|
142
142
|
hasCustomData: !!customAuthData
|
|
@@ -153,15 +153,30 @@ var ExpoAuthProvider = class {
|
|
|
153
153
|
if (result.type === "success" && result.url) {
|
|
154
154
|
const url = new URL(result.url);
|
|
155
155
|
const walletId = url.searchParams.get("wallet_id");
|
|
156
|
+
const organizationId = url.searchParams.get("organization_id");
|
|
156
157
|
const provider2 = url.searchParams.get("provider");
|
|
157
158
|
const accountDerivationIndex = url.searchParams.get("selected_account_index");
|
|
159
|
+
const expiresInMs = url.searchParams.get("expires_in_ms");
|
|
158
160
|
if (!walletId) {
|
|
159
161
|
throw new Error("Authentication failed: no walletId in redirect URL");
|
|
160
162
|
}
|
|
163
|
+
if (!organizationId) {
|
|
164
|
+
console.error("[ExpoAuthProvider] Missing organizationId in redirect URL", { url: result.url });
|
|
165
|
+
throw new Error("Authentication failed: no organizationId in redirect URL");
|
|
166
|
+
}
|
|
167
|
+
console.log("[ExpoAuthProvider] Auth redirect parameters", {
|
|
168
|
+
walletId,
|
|
169
|
+
organizationId,
|
|
170
|
+
provider: provider2,
|
|
171
|
+
accountDerivationIndex,
|
|
172
|
+
expiresInMs
|
|
173
|
+
});
|
|
161
174
|
return {
|
|
162
175
|
walletId,
|
|
176
|
+
organizationId,
|
|
163
177
|
provider: provider2 || void 0,
|
|
164
|
-
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) :
|
|
178
|
+
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
179
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
|
|
165
180
|
};
|
|
166
181
|
} else if (result.type === "cancel") {
|
|
167
182
|
throw new Error("User cancelled authentication");
|
|
@@ -262,7 +277,7 @@ var ReactNativeStamper = class {
|
|
|
262
277
|
this.algorithm = import_sdk_types.Algorithm.ed25519;
|
|
263
278
|
this.type = "PKI";
|
|
264
279
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
265
|
-
this.
|
|
280
|
+
this.appId = config.appId || "default";
|
|
266
281
|
}
|
|
267
282
|
/**
|
|
268
283
|
* Initialize the stamper and generate/load cryptographic keys
|
|
@@ -415,10 +430,10 @@ var ReactNativeStamper = class {
|
|
|
415
430
|
return null;
|
|
416
431
|
}
|
|
417
432
|
getActiveKeyName() {
|
|
418
|
-
return `${this.keyPrefix}-${this.
|
|
433
|
+
return `${this.keyPrefix}-${this.appId}-active`;
|
|
419
434
|
}
|
|
420
435
|
getPendingKeyName() {
|
|
421
|
-
return `${this.keyPrefix}-${this.
|
|
436
|
+
return `${this.keyPrefix}-${this.appId}-pending`;
|
|
422
437
|
}
|
|
423
438
|
};
|
|
424
439
|
|
|
@@ -459,34 +474,48 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
459
474
|
const [connectError, setConnectError] = (0, import_react.useState)(null);
|
|
460
475
|
const [addresses, setAddresses] = (0, import_react.useState)([]);
|
|
461
476
|
const [walletId, setWalletId] = (0, import_react.useState)(null);
|
|
462
|
-
const [sdk, setSdk] = (0, import_react.useState)(null);
|
|
463
477
|
const memoizedConfig = (0, import_react.useMemo)(() => {
|
|
464
478
|
const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
|
|
465
479
|
return {
|
|
466
480
|
...config,
|
|
481
|
+
apiBaseUrl: config.apiBaseUrl || import_constants2.DEFAULT_WALLET_API_URL,
|
|
482
|
+
embeddedWalletType: config.embeddedWalletType || import_constants2.DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
467
483
|
authOptions: {
|
|
468
484
|
...config.authOptions || {},
|
|
469
|
-
redirectUrl
|
|
485
|
+
redirectUrl,
|
|
486
|
+
authUrl: config.authOptions?.authUrl || import_constants2.DEFAULT_AUTH_URL
|
|
470
487
|
}
|
|
471
488
|
};
|
|
472
489
|
}, [config]);
|
|
473
|
-
(0, import_react.
|
|
490
|
+
const sdk = (0, import_react.useMemo)(() => {
|
|
474
491
|
const storage = new ExpoSecureStorage();
|
|
475
492
|
const authProvider = new ExpoAuthProvider();
|
|
476
493
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
477
494
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
478
495
|
const stamper = new ReactNativeStamper({
|
|
479
|
-
keyPrefix: `phantom-rn-${memoizedConfig.
|
|
480
|
-
|
|
496
|
+
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
497
|
+
appId: memoizedConfig.appId
|
|
481
498
|
});
|
|
499
|
+
const platformName = `${import_react_native2.Platform.OS}-${import_react_native2.Platform.Version}`;
|
|
482
500
|
const platform = {
|
|
483
501
|
storage,
|
|
484
502
|
authProvider,
|
|
485
503
|
urlParamsAccessor,
|
|
486
504
|
stamper,
|
|
487
|
-
name:
|
|
505
|
+
name: platformName,
|
|
506
|
+
analyticsHeaders: {
|
|
507
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
508
|
+
[import_constants2.ANALYTICS_HEADERS.PLATFORM]: import_react_native2.Platform.OS,
|
|
509
|
+
[import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native2.Platform.Version}`,
|
|
510
|
+
[import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
511
|
+
[import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
512
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.11"
|
|
513
|
+
// Replaced at build time
|
|
514
|
+
}
|
|
488
515
|
};
|
|
489
|
-
|
|
516
|
+
return new import_embedded_provider_core.EmbeddedProvider(memoizedConfig, platform, logger);
|
|
517
|
+
}, [memoizedConfig, debugConfig, config.appId, config.embeddedWalletType]);
|
|
518
|
+
(0, import_react.useEffect)(() => {
|
|
490
519
|
const handleConnectStart = () => {
|
|
491
520
|
setIsConnecting(true);
|
|
492
521
|
setConnectError(null);
|
|
@@ -495,12 +524,12 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
495
524
|
try {
|
|
496
525
|
setIsConnected(true);
|
|
497
526
|
setIsConnecting(false);
|
|
498
|
-
const addrs = await
|
|
527
|
+
const addrs = await sdk.getAddresses();
|
|
499
528
|
setAddresses(addrs);
|
|
500
529
|
} catch (err) {
|
|
501
530
|
console.error("Error connecting:", err);
|
|
502
531
|
try {
|
|
503
|
-
await
|
|
532
|
+
await sdk.disconnect();
|
|
504
533
|
} catch (err2) {
|
|
505
534
|
console.error("Error disconnecting:", err2);
|
|
506
535
|
}
|
|
@@ -517,21 +546,18 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
517
546
|
setAddresses([]);
|
|
518
547
|
setWalletId(null);
|
|
519
548
|
};
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
setSdk(sdkInstance);
|
|
549
|
+
sdk.on("connect_start", handleConnectStart);
|
|
550
|
+
sdk.on("connect", handleConnect);
|
|
551
|
+
sdk.on("connect_error", handleConnectError);
|
|
552
|
+
sdk.on("disconnect", handleDisconnect);
|
|
525
553
|
return () => {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
554
|
+
sdk.off("connect_start", handleConnectStart);
|
|
555
|
+
sdk.off("connect", handleConnect);
|
|
556
|
+
sdk.off("connect_error", handleConnectError);
|
|
557
|
+
sdk.off("disconnect", handleDisconnect);
|
|
530
558
|
};
|
|
531
|
-
}, [
|
|
559
|
+
}, [sdk]);
|
|
532
560
|
(0, import_react.useEffect)(() => {
|
|
533
|
-
if (!sdk)
|
|
534
|
-
return;
|
|
535
561
|
if (config.autoConnect !== false) {
|
|
536
562
|
sdk.autoConnect().catch(() => {
|
|
537
563
|
});
|
|
@@ -628,181 +654,30 @@ function useAccounts() {
|
|
|
628
654
|
}
|
|
629
655
|
|
|
630
656
|
// src/hooks/useSolana.ts
|
|
631
|
-
var import_react4 = require("react");
|
|
632
657
|
function useSolana() {
|
|
633
658
|
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
659
|
return {
|
|
694
|
-
// Chain instance for
|
|
695
|
-
solana:
|
|
696
|
-
// Convenient methods
|
|
697
|
-
signMessage,
|
|
698
|
-
signTransaction,
|
|
699
|
-
signAndSendTransaction,
|
|
700
|
-
connect,
|
|
701
|
-
disconnect,
|
|
702
|
-
switchNetwork,
|
|
703
|
-
getPublicKey,
|
|
660
|
+
// Chain instance with connection enforcement for signing methods
|
|
661
|
+
solana: sdk.solana,
|
|
704
662
|
// State
|
|
705
|
-
isAvailable: !!
|
|
706
|
-
isConnected: solanaChain?.isConnected() ?? false
|
|
663
|
+
isAvailable: !!isConnected
|
|
707
664
|
};
|
|
708
665
|
}
|
|
709
666
|
|
|
710
667
|
// src/hooks/useEthereum.ts
|
|
711
|
-
var import_react5 = require("react");
|
|
712
668
|
function useEthereum() {
|
|
713
669
|
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
670
|
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,
|
|
671
|
+
// Chain instance with connection enforcement for signing methods
|
|
672
|
+
ethereum: sdk.ethereum,
|
|
797
673
|
// State
|
|
798
|
-
isAvailable: !!
|
|
799
|
-
isConnected: ethereumChain?.isConnected() ?? false
|
|
674
|
+
isAvailable: !!isConnected
|
|
800
675
|
};
|
|
801
676
|
}
|
|
802
677
|
|
|
803
678
|
// src/index.ts
|
|
804
679
|
var import_client = require("@phantom/client");
|
|
805
|
-
var
|
|
680
|
+
var import_constants3 = require("@phantom/constants");
|
|
806
681
|
// Annotate the CommonJS export names for ESM import in node:
|
|
807
682
|
0 && (module.exports = {
|
|
808
683
|
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,29 +53,29 @@ 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,
|
|
63
|
+
const { authUrl, redirectUrl, publicKey, sessionId, provider, customAuthData, appId } = phantomOptions;
|
|
63
64
|
if (!redirectUrl) {
|
|
64
65
|
throw new Error("redirectUrl is required for web browser authentication");
|
|
65
66
|
}
|
|
66
|
-
if (!
|
|
67
|
-
throw new Error("
|
|
67
|
+
if (!publicKey || !sessionId || !appId) {
|
|
68
|
+
throw new Error("publicKey, sessionId and appId are required for authentication");
|
|
68
69
|
}
|
|
69
70
|
try {
|
|
70
71
|
const baseUrl = authUrl || DEFAULT_AUTH_URL;
|
|
71
72
|
const params = new URLSearchParams({
|
|
72
|
-
|
|
73
|
-
parent_organization_id: parentOrganizationId,
|
|
73
|
+
public_key: publicKey,
|
|
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.11"
|
|
78
79
|
});
|
|
79
80
|
if (provider) {
|
|
80
81
|
console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
|
|
@@ -91,8 +92,7 @@ var ExpoAuthProvider = class {
|
|
|
91
92
|
console.log("[ExpoAuthProvider] Starting authentication", {
|
|
92
93
|
baseUrl,
|
|
93
94
|
redirectUrl,
|
|
94
|
-
|
|
95
|
-
parentOrganizationId,
|
|
95
|
+
publicKey,
|
|
96
96
|
sessionId,
|
|
97
97
|
provider,
|
|
98
98
|
hasCustomData: !!customAuthData
|
|
@@ -109,15 +109,30 @@ var ExpoAuthProvider = class {
|
|
|
109
109
|
if (result.type === "success" && result.url) {
|
|
110
110
|
const url = new URL(result.url);
|
|
111
111
|
const walletId = url.searchParams.get("wallet_id");
|
|
112
|
+
const organizationId = url.searchParams.get("organization_id");
|
|
112
113
|
const provider2 = url.searchParams.get("provider");
|
|
113
114
|
const accountDerivationIndex = url.searchParams.get("selected_account_index");
|
|
115
|
+
const expiresInMs = url.searchParams.get("expires_in_ms");
|
|
114
116
|
if (!walletId) {
|
|
115
117
|
throw new Error("Authentication failed: no walletId in redirect URL");
|
|
116
118
|
}
|
|
119
|
+
if (!organizationId) {
|
|
120
|
+
console.error("[ExpoAuthProvider] Missing organizationId in redirect URL", { url: result.url });
|
|
121
|
+
throw new Error("Authentication failed: no organizationId in redirect URL");
|
|
122
|
+
}
|
|
123
|
+
console.log("[ExpoAuthProvider] Auth redirect parameters", {
|
|
124
|
+
walletId,
|
|
125
|
+
organizationId,
|
|
126
|
+
provider: provider2,
|
|
127
|
+
accountDerivationIndex,
|
|
128
|
+
expiresInMs
|
|
129
|
+
});
|
|
117
130
|
return {
|
|
118
131
|
walletId,
|
|
132
|
+
organizationId,
|
|
119
133
|
provider: provider2 || void 0,
|
|
120
|
-
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) :
|
|
134
|
+
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
135
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
|
|
121
136
|
};
|
|
122
137
|
} else if (result.type === "cancel") {
|
|
123
138
|
throw new Error("User cancelled authentication");
|
|
@@ -218,7 +233,7 @@ var ReactNativeStamper = class {
|
|
|
218
233
|
this.algorithm = Algorithm.ed25519;
|
|
219
234
|
this.type = "PKI";
|
|
220
235
|
this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
|
|
221
|
-
this.
|
|
236
|
+
this.appId = config.appId || "default";
|
|
222
237
|
}
|
|
223
238
|
/**
|
|
224
239
|
* Initialize the stamper and generate/load cryptographic keys
|
|
@@ -371,10 +386,10 @@ var ReactNativeStamper = class {
|
|
|
371
386
|
return null;
|
|
372
387
|
}
|
|
373
388
|
getActiveKeyName() {
|
|
374
|
-
return `${this.keyPrefix}-${this.
|
|
389
|
+
return `${this.keyPrefix}-${this.appId}-active`;
|
|
375
390
|
}
|
|
376
391
|
getPendingKeyName() {
|
|
377
|
-
return `${this.keyPrefix}-${this.
|
|
392
|
+
return `${this.keyPrefix}-${this.appId}-pending`;
|
|
378
393
|
}
|
|
379
394
|
};
|
|
380
395
|
|
|
@@ -415,34 +430,48 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
415
430
|
const [connectError, setConnectError] = useState(null);
|
|
416
431
|
const [addresses, setAddresses] = useState([]);
|
|
417
432
|
const [walletId, setWalletId] = useState(null);
|
|
418
|
-
const [sdk, setSdk] = useState(null);
|
|
419
433
|
const memoizedConfig = useMemo(() => {
|
|
420
434
|
const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
|
|
421
435
|
return {
|
|
422
436
|
...config,
|
|
437
|
+
apiBaseUrl: config.apiBaseUrl || DEFAULT_WALLET_API_URL,
|
|
438
|
+
embeddedWalletType: config.embeddedWalletType || DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
423
439
|
authOptions: {
|
|
424
440
|
...config.authOptions || {},
|
|
425
|
-
redirectUrl
|
|
441
|
+
redirectUrl,
|
|
442
|
+
authUrl: config.authOptions?.authUrl || DEFAULT_AUTH_URL2
|
|
426
443
|
}
|
|
427
444
|
};
|
|
428
445
|
}, [config]);
|
|
429
|
-
|
|
446
|
+
const sdk = useMemo(() => {
|
|
430
447
|
const storage = new ExpoSecureStorage();
|
|
431
448
|
const authProvider = new ExpoAuthProvider();
|
|
432
449
|
const urlParamsAccessor = new ExpoURLParamsAccessor();
|
|
433
450
|
const logger = new ExpoLogger(debugConfig?.enabled || false);
|
|
434
451
|
const stamper = new ReactNativeStamper({
|
|
435
|
-
keyPrefix: `phantom-rn-${memoizedConfig.
|
|
436
|
-
|
|
452
|
+
keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
|
|
453
|
+
appId: memoizedConfig.appId
|
|
437
454
|
});
|
|
455
|
+
const platformName = `${Platform.OS}-${Platform.Version}`;
|
|
438
456
|
const platform = {
|
|
439
457
|
storage,
|
|
440
458
|
authProvider,
|
|
441
459
|
urlParamsAccessor,
|
|
442
460
|
stamper,
|
|
443
|
-
name:
|
|
461
|
+
name: platformName,
|
|
462
|
+
analyticsHeaders: {
|
|
463
|
+
[ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
|
|
464
|
+
[ANALYTICS_HEADERS.PLATFORM]: Platform.OS,
|
|
465
|
+
[ANALYTICS_HEADERS.PLATFORM_VERSION]: `${Platform.Version}`,
|
|
466
|
+
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
467
|
+
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
468
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.11"
|
|
469
|
+
// Replaced at build time
|
|
470
|
+
}
|
|
444
471
|
};
|
|
445
|
-
|
|
472
|
+
return new EmbeddedProvider(memoizedConfig, platform, logger);
|
|
473
|
+
}, [memoizedConfig, debugConfig, config.appId, config.embeddedWalletType]);
|
|
474
|
+
useEffect(() => {
|
|
446
475
|
const handleConnectStart = () => {
|
|
447
476
|
setIsConnecting(true);
|
|
448
477
|
setConnectError(null);
|
|
@@ -451,12 +480,12 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
451
480
|
try {
|
|
452
481
|
setIsConnected(true);
|
|
453
482
|
setIsConnecting(false);
|
|
454
|
-
const addrs = await
|
|
483
|
+
const addrs = await sdk.getAddresses();
|
|
455
484
|
setAddresses(addrs);
|
|
456
485
|
} catch (err) {
|
|
457
486
|
console.error("Error connecting:", err);
|
|
458
487
|
try {
|
|
459
|
-
await
|
|
488
|
+
await sdk.disconnect();
|
|
460
489
|
} catch (err2) {
|
|
461
490
|
console.error("Error disconnecting:", err2);
|
|
462
491
|
}
|
|
@@ -473,21 +502,18 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
473
502
|
setAddresses([]);
|
|
474
503
|
setWalletId(null);
|
|
475
504
|
};
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
setSdk(sdkInstance);
|
|
505
|
+
sdk.on("connect_start", handleConnectStart);
|
|
506
|
+
sdk.on("connect", handleConnect);
|
|
507
|
+
sdk.on("connect_error", handleConnectError);
|
|
508
|
+
sdk.on("disconnect", handleDisconnect);
|
|
481
509
|
return () => {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
510
|
+
sdk.off("connect_start", handleConnectStart);
|
|
511
|
+
sdk.off("connect", handleConnect);
|
|
512
|
+
sdk.off("connect_error", handleConnectError);
|
|
513
|
+
sdk.off("disconnect", handleDisconnect);
|
|
486
514
|
};
|
|
487
|
-
}, [
|
|
515
|
+
}, [sdk]);
|
|
488
516
|
useEffect(() => {
|
|
489
|
-
if (!sdk)
|
|
490
|
-
return;
|
|
491
517
|
if (config.autoConnect !== false) {
|
|
492
518
|
sdk.autoConnect().catch(() => {
|
|
493
519
|
});
|
|
@@ -584,175 +610,24 @@ function useAccounts() {
|
|
|
584
610
|
}
|
|
585
611
|
|
|
586
612
|
// src/hooks/useSolana.ts
|
|
587
|
-
import { useCallback as useCallback3, useMemo as useMemo2 } from "react";
|
|
588
613
|
function useSolana() {
|
|
589
614
|
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
615
|
return {
|
|
650
|
-
// Chain instance for
|
|
651
|
-
solana:
|
|
652
|
-
// Convenient methods
|
|
653
|
-
signMessage,
|
|
654
|
-
signTransaction,
|
|
655
|
-
signAndSendTransaction,
|
|
656
|
-
connect,
|
|
657
|
-
disconnect,
|
|
658
|
-
switchNetwork,
|
|
659
|
-
getPublicKey,
|
|
616
|
+
// Chain instance with connection enforcement for signing methods
|
|
617
|
+
solana: sdk.solana,
|
|
660
618
|
// State
|
|
661
|
-
isAvailable: !!
|
|
662
|
-
isConnected: solanaChain?.isConnected() ?? false
|
|
619
|
+
isAvailable: !!isConnected
|
|
663
620
|
};
|
|
664
621
|
}
|
|
665
622
|
|
|
666
623
|
// src/hooks/useEthereum.ts
|
|
667
|
-
import { useCallback as useCallback4, useMemo as useMemo3 } from "react";
|
|
668
624
|
function useEthereum() {
|
|
669
625
|
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
626
|
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,
|
|
627
|
+
// Chain instance with connection enforcement for signing methods
|
|
628
|
+
ethereum: sdk.ethereum,
|
|
753
629
|
// State
|
|
754
|
-
isAvailable: !!
|
|
755
|
-
isConnected: ethereumChain?.isConnected() ?? false
|
|
630
|
+
isAvailable: !!isConnected
|
|
756
631
|
};
|
|
757
632
|
}
|
|
758
633
|
|
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.11",
|
|
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.11",
|
|
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.11",
|
|
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"
|