@phantom/react-native-sdk 0.1.7 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -28
- package/dist/index.d.ts +45 -15
- package/dist/index.js +166 -90
- package/dist/index.mjs +166 -90
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -113,12 +113,13 @@ export default function App() {
|
|
|
113
113
|
// WalletScreen.tsx
|
|
114
114
|
import React from "react";
|
|
115
115
|
import { View, Button, Text, Alert } from "react-native";
|
|
116
|
-
import { useConnect, useAccounts,
|
|
116
|
+
import { useConnect, useAccounts, useSolana, useEthereum, useDisconnect } from "@phantom/react-native-sdk";
|
|
117
117
|
|
|
118
118
|
export function WalletScreen() {
|
|
119
119
|
const { connect, isConnecting, error: connectError } = useConnect();
|
|
120
120
|
const { addresses, isConnected } = useAccounts();
|
|
121
|
-
const
|
|
121
|
+
const solana = useSolana();
|
|
122
|
+
const ethereum = useEthereum();
|
|
122
123
|
const { disconnect } = useDisconnect();
|
|
123
124
|
|
|
124
125
|
const handleConnect = async () => {
|
|
@@ -130,13 +131,20 @@ export function WalletScreen() {
|
|
|
130
131
|
}
|
|
131
132
|
};
|
|
132
133
|
|
|
133
|
-
const
|
|
134
|
+
const handleSignSolanaMessage = async () => {
|
|
134
135
|
try {
|
|
135
|
-
const signature = await signMessage(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
});
|
|
139
|
-
|
|
136
|
+
const signature = await solana.signMessage("Hello from Solana!");
|
|
137
|
+
Alert.alert("Solana Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
Alert.alert("Error", `Failed to sign: ${error.message}`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const handleSignEthereumMessage = async () => {
|
|
144
|
+
try {
|
|
145
|
+
const accounts = await ethereum.getAccounts();
|
|
146
|
+
const signature = await ethereum.signPersonalMessage("Hello from Ethereum!", accounts[0]);
|
|
147
|
+
Alert.alert("Ethereum Signed!", `Signature: ${signature.signature.slice(0, 10)}...`);
|
|
140
148
|
} catch (error) {
|
|
141
149
|
Alert.alert("Error", `Failed to sign: ${error.message}`);
|
|
142
150
|
}
|
|
@@ -158,12 +166,21 @@ export function WalletScreen() {
|
|
|
158
166
|
return (
|
|
159
167
|
<View style={{ padding: 20 }}>
|
|
160
168
|
<Text style={{ fontSize: 18, marginBottom: 10 }}>Wallet Connected</Text>
|
|
161
|
-
|
|
169
|
+
{addresses.map((addr, index) => (
|
|
170
|
+
<Text key={index}>
|
|
171
|
+
{addr.addressType}: {addr.address}
|
|
172
|
+
</Text>
|
|
173
|
+
))}
|
|
174
|
+
|
|
175
|
+
<Button
|
|
176
|
+
title="Sign Solana Message"
|
|
177
|
+
onPress={handleSignSolanaMessage}
|
|
178
|
+
style={{ marginTop: 10 }}
|
|
179
|
+
/>
|
|
162
180
|
|
|
163
181
|
<Button
|
|
164
|
-
title=
|
|
165
|
-
onPress={
|
|
166
|
-
disabled={isSigning}
|
|
182
|
+
title="Sign Ethereum Message"
|
|
183
|
+
onPress={handleSignEthereumMessage}
|
|
167
184
|
style={{ marginTop: 10 }}
|
|
168
185
|
/>
|
|
169
186
|
|
|
@@ -232,30 +249,38 @@ const {
|
|
|
232
249
|
} = useAccounts();
|
|
233
250
|
```
|
|
234
251
|
|
|
235
|
-
####
|
|
252
|
+
#### useSolana
|
|
236
253
|
|
|
237
|
-
|
|
254
|
+
Provides access to Solana-specific operations.
|
|
238
255
|
|
|
239
256
|
```typescript
|
|
240
|
-
const
|
|
257
|
+
const solana = useSolana();
|
|
258
|
+
|
|
259
|
+
// Sign a message
|
|
260
|
+
const signature = await solana.signMessage("Hello Solana!");
|
|
241
261
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
networkId: "solana:mainnet", // or 'ethereum:1'
|
|
245
|
-
});
|
|
262
|
+
// Sign and send a transaction
|
|
263
|
+
const result = await solana.signAndSendTransaction(transaction);
|
|
246
264
|
```
|
|
247
265
|
|
|
248
|
-
####
|
|
266
|
+
#### useEthereum
|
|
249
267
|
|
|
250
|
-
|
|
268
|
+
Provides access to Ethereum-specific operations.
|
|
251
269
|
|
|
252
270
|
```typescript
|
|
253
|
-
const
|
|
271
|
+
const ethereum = useEthereum();
|
|
272
|
+
|
|
273
|
+
// Get accounts
|
|
274
|
+
const accounts = await ethereum.getAccounts();
|
|
275
|
+
|
|
276
|
+
// Sign a personal message
|
|
277
|
+
const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
|
|
278
|
+
|
|
279
|
+
// Send a transaction
|
|
280
|
+
const result = await ethereum.sendTransaction(transactionData);
|
|
254
281
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
networkId: NetworkId.SOLANA_MAINNET,
|
|
258
|
-
});
|
|
282
|
+
// Get current chain ID
|
|
283
|
+
const chainId = await ethereum.getChainId();
|
|
259
284
|
```
|
|
260
285
|
|
|
261
286
|
#### useDisconnect
|
|
@@ -328,7 +353,7 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
|
|
|
328
353
|
</PhantomProvider>;
|
|
329
354
|
```
|
|
330
355
|
|
|
331
|
-
###
|
|
356
|
+
### Multi-Chain Configuration
|
|
332
357
|
|
|
333
358
|
```tsx
|
|
334
359
|
import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
|
|
@@ -340,8 +365,9 @@ import { PhantomProvider, AddressType } from "@phantom/react-native-sdk";
|
|
|
340
365
|
embeddedWalletType: "user-wallet",
|
|
341
366
|
addressTypes: [AddressType.solana, AddressType.ethereum],
|
|
342
367
|
apiBaseUrl: "https://api.phantom.app/v1/wallets",
|
|
368
|
+
solanaProvider: "web3js",
|
|
343
369
|
authOptions: {
|
|
344
|
-
authUrl: "https://
|
|
370
|
+
authUrl: "https://connect.phantom.app",
|
|
345
371
|
redirectUrl: "mycompany-wallet://auth/success",
|
|
346
372
|
},
|
|
347
373
|
}}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import * as _phantom_embedded_provider_core from '@phantom/embedded-provider-core';
|
|
4
|
-
import { EmbeddedProviderConfig, EmbeddedProvider, WalletAddress, ConnectResult
|
|
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, EthTransactionRequest } from '@phantom/chains';
|
|
7
|
+
import { ParsedSignatureResult, ParsedTransactionResult } from '@phantom/parsers';
|
|
6
8
|
export { AddressType } from '@phantom/client';
|
|
7
9
|
export { NetworkId } from '@phantom/constants';
|
|
8
10
|
|
|
@@ -40,14 +42,10 @@ interface PhantomProviderProps {
|
|
|
40
42
|
debugConfig?: PhantomDebugConfig;
|
|
41
43
|
}
|
|
42
44
|
declare function PhantomProvider({ children, config, debugConfig }: PhantomProviderProps): react_jsx_runtime.JSX.Element;
|
|
43
|
-
/**
|
|
44
|
-
* Hook to access the Phantom context
|
|
45
|
-
* Must be used within a PhantomProvider
|
|
46
|
-
*/
|
|
47
45
|
declare function usePhantom(): PhantomContextValue;
|
|
48
46
|
|
|
49
47
|
declare function useConnect(): {
|
|
50
|
-
connect: (
|
|
48
|
+
connect: (_options?: ConnectOptions) => Promise<ConnectResult>;
|
|
51
49
|
isConnecting: boolean;
|
|
52
50
|
error: Error | null;
|
|
53
51
|
};
|
|
@@ -64,16 +62,48 @@ declare function useAccounts(): {
|
|
|
64
62
|
walletId: string | null;
|
|
65
63
|
};
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Hook for Solana chain operations in React Native
|
|
67
|
+
*
|
|
68
|
+
* @returns Solana chain interface and convenient methods
|
|
69
|
+
*/
|
|
70
|
+
declare function useSolana(): {
|
|
71
|
+
solana: ISolanaChain | null;
|
|
72
|
+
signMessage: (message: string | Uint8Array) => Promise<ParsedSignatureResult>;
|
|
73
|
+
signTransaction: <T>(transaction: T) => Promise<T>;
|
|
74
|
+
signAndSendTransaction: <T>(transaction: T) => Promise<ParsedTransactionResult>;
|
|
75
|
+
connect: (options?: {
|
|
76
|
+
onlyIfTrusted?: boolean;
|
|
77
|
+
}) => Promise<{
|
|
78
|
+
publicKey: string;
|
|
79
|
+
}>;
|
|
80
|
+
disconnect: () => Promise<void>;
|
|
81
|
+
switchNetwork: (network: "mainnet" | "devnet") => Promise<void>;
|
|
82
|
+
getPublicKey: () => Promise<string | null>;
|
|
83
|
+
isAvailable: boolean;
|
|
84
|
+
isConnected: boolean;
|
|
71
85
|
};
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Hook for Ethereum chain operations in React Native
|
|
89
|
+
*
|
|
90
|
+
* @returns Ethereum chain interface and convenient methods
|
|
91
|
+
*/
|
|
92
|
+
declare function useEthereum(): {
|
|
93
|
+
ethereum: IEthereumChain | null;
|
|
94
|
+
request: <T = any>(args: {
|
|
95
|
+
method: string;
|
|
96
|
+
params?: unknown[];
|
|
97
|
+
}) => Promise<T>;
|
|
98
|
+
signPersonalMessage: (message: string, address: string) => Promise<ParsedSignatureResult>;
|
|
99
|
+
signMessage: (message: string) => Promise<string>;
|
|
100
|
+
signTypedData: (typedData: any) => Promise<ParsedSignatureResult>;
|
|
101
|
+
sendTransaction: (transaction: EthTransactionRequest) => Promise<ParsedTransactionResult>;
|
|
102
|
+
switchChain: (chainId: number) => Promise<void>;
|
|
103
|
+
getChainId: () => Promise<number>;
|
|
104
|
+
getAccounts: () => Promise<string[]>;
|
|
105
|
+
isAvailable: boolean;
|
|
106
|
+
isConnected: boolean;
|
|
77
107
|
};
|
|
78
108
|
|
|
79
|
-
export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomSDKConfig, useAccounts, useConnect, useDisconnect,
|
|
109
|
+
export { ConnectOptions, PhantomDebugConfig, PhantomProvider, PhantomSDKConfig, useAccounts, useConnect, useDisconnect, useEthereum, usePhantom, useSolana };
|
package/dist/index.js
CHANGED
|
@@ -36,9 +36,9 @@ __export(src_exports, {
|
|
|
36
36
|
useAccounts: () => useAccounts,
|
|
37
37
|
useConnect: () => useConnect,
|
|
38
38
|
useDisconnect: () => useDisconnect,
|
|
39
|
+
useEthereum: () => useEthereum,
|
|
39
40
|
usePhantom: () => usePhantom,
|
|
40
|
-
|
|
41
|
-
useSignMessage: () => useSignMessage
|
|
41
|
+
useSolana: () => useSolana
|
|
42
42
|
});
|
|
43
43
|
module.exports = __toCommonJS(src_exports);
|
|
44
44
|
|
|
@@ -167,12 +167,14 @@ var ExpoAuthProvider = class {
|
|
|
167
167
|
const url = new URL(result.url);
|
|
168
168
|
const walletId = url.searchParams.get("wallet_id");
|
|
169
169
|
const provider2 = url.searchParams.get("provider");
|
|
170
|
+
const accountDerivationIndex = url.searchParams.get("selected_account_index");
|
|
170
171
|
if (!walletId) {
|
|
171
172
|
throw new Error("Authentication failed: no walletId in redirect URL");
|
|
172
173
|
}
|
|
173
174
|
return {
|
|
174
175
|
walletId,
|
|
175
|
-
provider: provider2 || void 0
|
|
176
|
+
provider: provider2 || void 0,
|
|
177
|
+
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : void 0
|
|
176
178
|
};
|
|
177
179
|
} else if (result.type === "cancel") {
|
|
178
180
|
throw new Error("User cancelled authentication");
|
|
@@ -259,33 +261,6 @@ var ExpoURLParamsAccessor = class {
|
|
|
259
261
|
}
|
|
260
262
|
};
|
|
261
263
|
|
|
262
|
-
// src/providers/embedded/logger.ts
|
|
263
|
-
var ExpoLogger = class {
|
|
264
|
-
constructor(enabled = false) {
|
|
265
|
-
this.enabled = enabled;
|
|
266
|
-
}
|
|
267
|
-
info(category, message, data) {
|
|
268
|
-
if (this.enabled) {
|
|
269
|
-
console.info(`[${category}] ${message}`, data);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
warn(category, message, data) {
|
|
273
|
-
if (this.enabled) {
|
|
274
|
-
console.warn(`[${category}] ${message}`, data);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
error(category, message, data) {
|
|
278
|
-
if (this.enabled) {
|
|
279
|
-
console.error(`[${category}] ${message}`, data);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
log(category, message, data) {
|
|
283
|
-
if (this.enabled) {
|
|
284
|
-
console.log(`[${category}] ${message}`, data);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
264
|
// src/providers/embedded/stamper.ts
|
|
290
265
|
var SecureStore2 = __toESM(require("expo-secure-store"));
|
|
291
266
|
var import_api_key_stamper = require("@phantom/api-key-stamper");
|
|
@@ -460,6 +435,33 @@ var ReactNativeStamper = class {
|
|
|
460
435
|
}
|
|
461
436
|
};
|
|
462
437
|
|
|
438
|
+
// src/providers/embedded/logger.ts
|
|
439
|
+
var ExpoLogger = class {
|
|
440
|
+
constructor(enabled = false) {
|
|
441
|
+
this.enabled = enabled;
|
|
442
|
+
}
|
|
443
|
+
info(category, message, data) {
|
|
444
|
+
if (this.enabled) {
|
|
445
|
+
console.info(`[${category}] ${message}`, data);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
warn(category, message, data) {
|
|
449
|
+
if (this.enabled) {
|
|
450
|
+
console.warn(`[${category}] ${message}`, data);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
error(category, message, data) {
|
|
454
|
+
if (this.enabled) {
|
|
455
|
+
console.error(`[${category}] ${message}`, data);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
log(category, message, data) {
|
|
459
|
+
if (this.enabled) {
|
|
460
|
+
console.log(`[${category}] ${message}`, data);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
|
|
463
465
|
// src/PhantomProvider.tsx
|
|
464
466
|
var import_react_native2 = require("react-native");
|
|
465
467
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -572,7 +574,7 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
572
574
|
}
|
|
573
575
|
function usePhantom() {
|
|
574
576
|
const context = (0, import_react.useContext)(PhantomContext);
|
|
575
|
-
if (
|
|
577
|
+
if (context === void 0) {
|
|
576
578
|
throw new Error("usePhantom must be used within a PhantomProvider");
|
|
577
579
|
}
|
|
578
580
|
return context;
|
|
@@ -583,12 +585,12 @@ var import_react2 = require("react");
|
|
|
583
585
|
function useConnect() {
|
|
584
586
|
const { sdk, isConnecting, connectError, setWalletId } = usePhantom();
|
|
585
587
|
const connect = (0, import_react2.useCallback)(
|
|
586
|
-
async (
|
|
588
|
+
async (_options) => {
|
|
587
589
|
if (!sdk) {
|
|
588
590
|
throw new Error("SDK not initialized");
|
|
589
591
|
}
|
|
590
592
|
try {
|
|
591
|
-
const result = await sdk.connect(
|
|
593
|
+
const result = await sdk.connect();
|
|
592
594
|
if (result.status === "completed" && result.walletId) {
|
|
593
595
|
setWalletId(result.walletId);
|
|
594
596
|
}
|
|
@@ -646,69 +648,143 @@ function useAccounts() {
|
|
|
646
648
|
};
|
|
647
649
|
}
|
|
648
650
|
|
|
649
|
-
// src/hooks/
|
|
651
|
+
// src/hooks/useSolana.ts
|
|
650
652
|
var import_react4 = require("react");
|
|
651
|
-
function
|
|
652
|
-
const { sdk } = usePhantom();
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
653
|
+
function useSolana() {
|
|
654
|
+
const { sdk, isConnected } = usePhantom();
|
|
655
|
+
const solanaChain = (0, import_react4.useMemo)(() => {
|
|
656
|
+
if (!sdk || !isConnected)
|
|
657
|
+
return null;
|
|
658
|
+
try {
|
|
659
|
+
return sdk.solana;
|
|
660
|
+
} catch {
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
}, [sdk, isConnected]);
|
|
664
|
+
const signMessage = (0, import_react4.useCallback)(async (message) => {
|
|
665
|
+
if (!solanaChain)
|
|
666
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
667
|
+
return await solanaChain.signMessage(message);
|
|
668
|
+
}, [solanaChain]);
|
|
669
|
+
const signTransaction = (0, import_react4.useCallback)(async (transaction) => {
|
|
670
|
+
if (!solanaChain)
|
|
671
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
672
|
+
return await solanaChain.signTransaction(transaction);
|
|
673
|
+
}, [solanaChain]);
|
|
674
|
+
const signAndSendTransaction = (0, import_react4.useCallback)(async (transaction) => {
|
|
675
|
+
if (!solanaChain)
|
|
676
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
677
|
+
return await solanaChain.signAndSendTransaction(transaction);
|
|
678
|
+
}, [solanaChain]);
|
|
679
|
+
const connect = (0, import_react4.useCallback)(async (options) => {
|
|
680
|
+
if (!solanaChain)
|
|
681
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
682
|
+
return await solanaChain.connect(options);
|
|
683
|
+
}, [solanaChain]);
|
|
684
|
+
const disconnect = (0, import_react4.useCallback)(async () => {
|
|
685
|
+
if (!solanaChain)
|
|
686
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
687
|
+
return await solanaChain.disconnect();
|
|
688
|
+
}, [solanaChain]);
|
|
689
|
+
const switchNetwork = (0, import_react4.useCallback)(async (network) => {
|
|
690
|
+
if (!solanaChain)
|
|
691
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
692
|
+
return await solanaChain.switchNetwork(network);
|
|
693
|
+
}, [solanaChain]);
|
|
694
|
+
const getPublicKey = (0, import_react4.useCallback)(async () => {
|
|
695
|
+
if (!solanaChain)
|
|
696
|
+
return null;
|
|
697
|
+
return await solanaChain.getPublicKey();
|
|
698
|
+
}, [solanaChain]);
|
|
675
699
|
return {
|
|
700
|
+
// Chain instance for advanced usage
|
|
701
|
+
solana: solanaChain,
|
|
702
|
+
// Convenient methods
|
|
676
703
|
signMessage,
|
|
677
|
-
|
|
678
|
-
|
|
704
|
+
signTransaction,
|
|
705
|
+
signAndSendTransaction,
|
|
706
|
+
connect,
|
|
707
|
+
disconnect,
|
|
708
|
+
switchNetwork,
|
|
709
|
+
getPublicKey,
|
|
710
|
+
// State
|
|
711
|
+
isAvailable: !!solanaChain,
|
|
712
|
+
isConnected: solanaChain?.isConnected() ?? false
|
|
679
713
|
};
|
|
680
714
|
}
|
|
681
715
|
|
|
682
|
-
// src/hooks/
|
|
716
|
+
// src/hooks/useEthereum.ts
|
|
683
717
|
var import_react5 = require("react");
|
|
684
|
-
function
|
|
685
|
-
const { sdk } = usePhantom();
|
|
686
|
-
const
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
718
|
+
function useEthereum() {
|
|
719
|
+
const { sdk, isConnected } = usePhantom();
|
|
720
|
+
const ethereumChain = (0, import_react5.useMemo)(() => {
|
|
721
|
+
if (!sdk || !isConnected)
|
|
722
|
+
return null;
|
|
723
|
+
try {
|
|
724
|
+
return sdk.ethereum;
|
|
725
|
+
} catch {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
}, [sdk, isConnected]);
|
|
729
|
+
const request = (0, import_react5.useCallback)(async (args) => {
|
|
730
|
+
if (!ethereumChain)
|
|
731
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
732
|
+
return await ethereumChain.request(args);
|
|
733
|
+
}, [ethereumChain]);
|
|
734
|
+
const signPersonalMessage = (0, import_react5.useCallback)(async (message, address) => {
|
|
735
|
+
if (!ethereumChain)
|
|
736
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
737
|
+
return await ethereumChain.signPersonalMessage(message, address);
|
|
738
|
+
}, [ethereumChain]);
|
|
739
|
+
const sendTransaction = (0, import_react5.useCallback)(async (transaction) => {
|
|
740
|
+
if (!ethereumChain)
|
|
741
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
742
|
+
return await ethereumChain.sendTransaction(transaction);
|
|
743
|
+
}, [ethereumChain]);
|
|
744
|
+
const switchChain = (0, import_react5.useCallback)(async (chainId) => {
|
|
745
|
+
if (!ethereumChain)
|
|
746
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
747
|
+
return await ethereumChain.switchChain(chainId);
|
|
748
|
+
}, [ethereumChain]);
|
|
749
|
+
const getChainId = (0, import_react5.useCallback)(async () => {
|
|
750
|
+
if (!ethereumChain)
|
|
751
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
752
|
+
return await ethereumChain.getChainId();
|
|
753
|
+
}, [ethereumChain]);
|
|
754
|
+
const getAccounts = (0, import_react5.useCallback)(async () => {
|
|
755
|
+
if (!ethereumChain)
|
|
756
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
757
|
+
return await ethereumChain.getAccounts();
|
|
758
|
+
}, [ethereumChain]);
|
|
759
|
+
const signMessage = (0, import_react5.useCallback)(async (message) => {
|
|
760
|
+
const accounts = await getAccounts();
|
|
761
|
+
return await request({
|
|
762
|
+
method: "eth_sign",
|
|
763
|
+
params: [accounts[0], message]
|
|
764
|
+
});
|
|
765
|
+
}, [request, getAccounts]);
|
|
766
|
+
const signTypedData = (0, import_react5.useCallback)(async (typedData) => {
|
|
767
|
+
if (!ethereumChain)
|
|
768
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
769
|
+
const accounts = await getAccounts();
|
|
770
|
+
return await ethereumChain.signTypedData(typedData, accounts[0]);
|
|
771
|
+
}, [ethereumChain, getAccounts]);
|
|
708
772
|
return {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
773
|
+
// Chain instance for advanced usage
|
|
774
|
+
ethereum: ethereumChain,
|
|
775
|
+
// Standard EIP-1193 interface
|
|
776
|
+
request,
|
|
777
|
+
// Convenient methods
|
|
778
|
+
signPersonalMessage,
|
|
779
|
+
signMessage,
|
|
780
|
+
signTypedData,
|
|
781
|
+
sendTransaction,
|
|
782
|
+
switchChain,
|
|
783
|
+
getChainId,
|
|
784
|
+
getAccounts,
|
|
785
|
+
// State
|
|
786
|
+
isAvailable: !!ethereumChain,
|
|
787
|
+
isConnected: ethereumChain?.isConnected() ?? false
|
|
712
788
|
};
|
|
713
789
|
}
|
|
714
790
|
|
|
@@ -723,7 +799,7 @@ var import_constants = require("@phantom/constants");
|
|
|
723
799
|
useAccounts,
|
|
724
800
|
useConnect,
|
|
725
801
|
useDisconnect,
|
|
802
|
+
useEthereum,
|
|
726
803
|
usePhantom,
|
|
727
|
-
|
|
728
|
-
useSignMessage
|
|
804
|
+
useSolana
|
|
729
805
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -123,12 +123,14 @@ var ExpoAuthProvider = class {
|
|
|
123
123
|
const url = new URL(result.url);
|
|
124
124
|
const walletId = url.searchParams.get("wallet_id");
|
|
125
125
|
const provider2 = url.searchParams.get("provider");
|
|
126
|
+
const accountDerivationIndex = url.searchParams.get("selected_account_index");
|
|
126
127
|
if (!walletId) {
|
|
127
128
|
throw new Error("Authentication failed: no walletId in redirect URL");
|
|
128
129
|
}
|
|
129
130
|
return {
|
|
130
131
|
walletId,
|
|
131
|
-
provider: provider2 || void 0
|
|
132
|
+
provider: provider2 || void 0,
|
|
133
|
+
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : void 0
|
|
132
134
|
};
|
|
133
135
|
} else if (result.type === "cancel") {
|
|
134
136
|
throw new Error("User cancelled authentication");
|
|
@@ -215,33 +217,6 @@ var ExpoURLParamsAccessor = class {
|
|
|
215
217
|
}
|
|
216
218
|
};
|
|
217
219
|
|
|
218
|
-
// src/providers/embedded/logger.ts
|
|
219
|
-
var ExpoLogger = class {
|
|
220
|
-
constructor(enabled = false) {
|
|
221
|
-
this.enabled = enabled;
|
|
222
|
-
}
|
|
223
|
-
info(category, message, data) {
|
|
224
|
-
if (this.enabled) {
|
|
225
|
-
console.info(`[${category}] ${message}`, data);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
warn(category, message, data) {
|
|
229
|
-
if (this.enabled) {
|
|
230
|
-
console.warn(`[${category}] ${message}`, data);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
error(category, message, data) {
|
|
234
|
-
if (this.enabled) {
|
|
235
|
-
console.error(`[${category}] ${message}`, data);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
log(category, message, data) {
|
|
239
|
-
if (this.enabled) {
|
|
240
|
-
console.log(`[${category}] ${message}`, data);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
|
|
245
220
|
// src/providers/embedded/stamper.ts
|
|
246
221
|
import * as SecureStore2 from "expo-secure-store";
|
|
247
222
|
import { ApiKeyStamper } from "@phantom/api-key-stamper";
|
|
@@ -416,6 +391,33 @@ var ReactNativeStamper = class {
|
|
|
416
391
|
}
|
|
417
392
|
};
|
|
418
393
|
|
|
394
|
+
// src/providers/embedded/logger.ts
|
|
395
|
+
var ExpoLogger = class {
|
|
396
|
+
constructor(enabled = false) {
|
|
397
|
+
this.enabled = enabled;
|
|
398
|
+
}
|
|
399
|
+
info(category, message, data) {
|
|
400
|
+
if (this.enabled) {
|
|
401
|
+
console.info(`[${category}] ${message}`, data);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
warn(category, message, data) {
|
|
405
|
+
if (this.enabled) {
|
|
406
|
+
console.warn(`[${category}] ${message}`, data);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
error(category, message, data) {
|
|
410
|
+
if (this.enabled) {
|
|
411
|
+
console.error(`[${category}] ${message}`, data);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
log(category, message, data) {
|
|
415
|
+
if (this.enabled) {
|
|
416
|
+
console.log(`[${category}] ${message}`, data);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
419
421
|
// src/PhantomProvider.tsx
|
|
420
422
|
import { Platform } from "react-native";
|
|
421
423
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -528,7 +530,7 @@ function PhantomProvider({ children, config, debugConfig }) {
|
|
|
528
530
|
}
|
|
529
531
|
function usePhantom() {
|
|
530
532
|
const context = useContext(PhantomContext);
|
|
531
|
-
if (
|
|
533
|
+
if (context === void 0) {
|
|
532
534
|
throw new Error("usePhantom must be used within a PhantomProvider");
|
|
533
535
|
}
|
|
534
536
|
return context;
|
|
@@ -539,12 +541,12 @@ import { useCallback } from "react";
|
|
|
539
541
|
function useConnect() {
|
|
540
542
|
const { sdk, isConnecting, connectError, setWalletId } = usePhantom();
|
|
541
543
|
const connect = useCallback(
|
|
542
|
-
async (
|
|
544
|
+
async (_options) => {
|
|
543
545
|
if (!sdk) {
|
|
544
546
|
throw new Error("SDK not initialized");
|
|
545
547
|
}
|
|
546
548
|
try {
|
|
547
|
-
const result = await sdk.connect(
|
|
549
|
+
const result = await sdk.connect();
|
|
548
550
|
if (result.status === "completed" && result.walletId) {
|
|
549
551
|
setWalletId(result.walletId);
|
|
550
552
|
}
|
|
@@ -602,69 +604,143 @@ function useAccounts() {
|
|
|
602
604
|
};
|
|
603
605
|
}
|
|
604
606
|
|
|
605
|
-
// src/hooks/
|
|
606
|
-
import {
|
|
607
|
-
function
|
|
608
|
-
const { sdk } = usePhantom();
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
607
|
+
// src/hooks/useSolana.ts
|
|
608
|
+
import { useCallback as useCallback3, useMemo as useMemo2 } from "react";
|
|
609
|
+
function useSolana() {
|
|
610
|
+
const { sdk, isConnected } = usePhantom();
|
|
611
|
+
const solanaChain = useMemo2(() => {
|
|
612
|
+
if (!sdk || !isConnected)
|
|
613
|
+
return null;
|
|
614
|
+
try {
|
|
615
|
+
return sdk.solana;
|
|
616
|
+
} catch {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
}, [sdk, isConnected]);
|
|
620
|
+
const signMessage = useCallback3(async (message) => {
|
|
621
|
+
if (!solanaChain)
|
|
622
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
623
|
+
return await solanaChain.signMessage(message);
|
|
624
|
+
}, [solanaChain]);
|
|
625
|
+
const signTransaction = useCallback3(async (transaction) => {
|
|
626
|
+
if (!solanaChain)
|
|
627
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
628
|
+
return await solanaChain.signTransaction(transaction);
|
|
629
|
+
}, [solanaChain]);
|
|
630
|
+
const signAndSendTransaction = useCallback3(async (transaction) => {
|
|
631
|
+
if (!solanaChain)
|
|
632
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
633
|
+
return await solanaChain.signAndSendTransaction(transaction);
|
|
634
|
+
}, [solanaChain]);
|
|
635
|
+
const connect = useCallback3(async (options) => {
|
|
636
|
+
if (!solanaChain)
|
|
637
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
638
|
+
return await solanaChain.connect(options);
|
|
639
|
+
}, [solanaChain]);
|
|
640
|
+
const disconnect = useCallback3(async () => {
|
|
641
|
+
if (!solanaChain)
|
|
642
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
643
|
+
return await solanaChain.disconnect();
|
|
644
|
+
}, [solanaChain]);
|
|
645
|
+
const switchNetwork = useCallback3(async (network) => {
|
|
646
|
+
if (!solanaChain)
|
|
647
|
+
throw new Error("Solana chain not available. Ensure SDK is connected.");
|
|
648
|
+
return await solanaChain.switchNetwork(network);
|
|
649
|
+
}, [solanaChain]);
|
|
650
|
+
const getPublicKey = useCallback3(async () => {
|
|
651
|
+
if (!solanaChain)
|
|
652
|
+
return null;
|
|
653
|
+
return await solanaChain.getPublicKey();
|
|
654
|
+
}, [solanaChain]);
|
|
631
655
|
return {
|
|
656
|
+
// Chain instance for advanced usage
|
|
657
|
+
solana: solanaChain,
|
|
658
|
+
// Convenient methods
|
|
632
659
|
signMessage,
|
|
633
|
-
|
|
634
|
-
|
|
660
|
+
signTransaction,
|
|
661
|
+
signAndSendTransaction,
|
|
662
|
+
connect,
|
|
663
|
+
disconnect,
|
|
664
|
+
switchNetwork,
|
|
665
|
+
getPublicKey,
|
|
666
|
+
// State
|
|
667
|
+
isAvailable: !!solanaChain,
|
|
668
|
+
isConnected: solanaChain?.isConnected() ?? false
|
|
635
669
|
};
|
|
636
670
|
}
|
|
637
671
|
|
|
638
|
-
// src/hooks/
|
|
639
|
-
import {
|
|
640
|
-
function
|
|
641
|
-
const { sdk } = usePhantom();
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
672
|
+
// src/hooks/useEthereum.ts
|
|
673
|
+
import { useCallback as useCallback4, useMemo as useMemo3 } from "react";
|
|
674
|
+
function useEthereum() {
|
|
675
|
+
const { sdk, isConnected } = usePhantom();
|
|
676
|
+
const ethereumChain = useMemo3(() => {
|
|
677
|
+
if (!sdk || !isConnected)
|
|
678
|
+
return null;
|
|
679
|
+
try {
|
|
680
|
+
return sdk.ethereum;
|
|
681
|
+
} catch {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
}, [sdk, isConnected]);
|
|
685
|
+
const request = useCallback4(async (args) => {
|
|
686
|
+
if (!ethereumChain)
|
|
687
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
688
|
+
return await ethereumChain.request(args);
|
|
689
|
+
}, [ethereumChain]);
|
|
690
|
+
const signPersonalMessage = useCallback4(async (message, address) => {
|
|
691
|
+
if (!ethereumChain)
|
|
692
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
693
|
+
return await ethereumChain.signPersonalMessage(message, address);
|
|
694
|
+
}, [ethereumChain]);
|
|
695
|
+
const sendTransaction = useCallback4(async (transaction) => {
|
|
696
|
+
if (!ethereumChain)
|
|
697
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
698
|
+
return await ethereumChain.sendTransaction(transaction);
|
|
699
|
+
}, [ethereumChain]);
|
|
700
|
+
const switchChain = useCallback4(async (chainId) => {
|
|
701
|
+
if (!ethereumChain)
|
|
702
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
703
|
+
return await ethereumChain.switchChain(chainId);
|
|
704
|
+
}, [ethereumChain]);
|
|
705
|
+
const getChainId = useCallback4(async () => {
|
|
706
|
+
if (!ethereumChain)
|
|
707
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
708
|
+
return await ethereumChain.getChainId();
|
|
709
|
+
}, [ethereumChain]);
|
|
710
|
+
const getAccounts = useCallback4(async () => {
|
|
711
|
+
if (!ethereumChain)
|
|
712
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
713
|
+
return await ethereumChain.getAccounts();
|
|
714
|
+
}, [ethereumChain]);
|
|
715
|
+
const signMessage = useCallback4(async (message) => {
|
|
716
|
+
const accounts = await getAccounts();
|
|
717
|
+
return await request({
|
|
718
|
+
method: "eth_sign",
|
|
719
|
+
params: [accounts[0], message]
|
|
720
|
+
});
|
|
721
|
+
}, [request, getAccounts]);
|
|
722
|
+
const signTypedData = useCallback4(async (typedData) => {
|
|
723
|
+
if (!ethereumChain)
|
|
724
|
+
throw new Error("Ethereum chain not available. Ensure SDK is connected.");
|
|
725
|
+
const accounts = await getAccounts();
|
|
726
|
+
return await ethereumChain.signTypedData(typedData, accounts[0]);
|
|
727
|
+
}, [ethereumChain, getAccounts]);
|
|
664
728
|
return {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
729
|
+
// Chain instance for advanced usage
|
|
730
|
+
ethereum: ethereumChain,
|
|
731
|
+
// Standard EIP-1193 interface
|
|
732
|
+
request,
|
|
733
|
+
// Convenient methods
|
|
734
|
+
signPersonalMessage,
|
|
735
|
+
signMessage,
|
|
736
|
+
signTypedData,
|
|
737
|
+
sendTransaction,
|
|
738
|
+
switchChain,
|
|
739
|
+
getChainId,
|
|
740
|
+
getAccounts,
|
|
741
|
+
// State
|
|
742
|
+
isAvailable: !!ethereumChain,
|
|
743
|
+
isConnected: ethereumChain?.isConnected() ?? false
|
|
668
744
|
};
|
|
669
745
|
}
|
|
670
746
|
|
|
@@ -678,7 +754,7 @@ export {
|
|
|
678
754
|
useAccounts,
|
|
679
755
|
useConnect,
|
|
680
756
|
useDisconnect,
|
|
757
|
+
useEthereum,
|
|
681
758
|
usePhantom,
|
|
682
|
-
|
|
683
|
-
useSignMessage
|
|
759
|
+
useSolana
|
|
684
760
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/react-native-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
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,13 +45,15 @@
|
|
|
45
45
|
"directory": "packages/react-native-sdk"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@phantom/api-key-stamper": "^0.
|
|
49
|
-
"@phantom/base64url": "^0.
|
|
50
|
-
"@phantom/
|
|
51
|
-
"@phantom/
|
|
52
|
-
"@phantom/
|
|
53
|
-
"@phantom/
|
|
54
|
-
"@phantom/
|
|
48
|
+
"@phantom/api-key-stamper": "^1.0.0-beta.0",
|
|
49
|
+
"@phantom/base64url": "^1.0.0-beta.0",
|
|
50
|
+
"@phantom/chains": "^1.0.0-beta.0",
|
|
51
|
+
"@phantom/client": "^1.0.0-beta.0",
|
|
52
|
+
"@phantom/constants": "^1.0.0-beta.0",
|
|
53
|
+
"@phantom/crypto": "^1.0.0-beta.0",
|
|
54
|
+
"@phantom/embedded-provider-core": "^1.0.0-beta.0",
|
|
55
|
+
"@phantom/parsers": "^1.0.0-beta.0",
|
|
56
|
+
"@phantom/sdk-types": "^1.0.0-beta.0",
|
|
55
57
|
"@types/bs58": "^5.0.0",
|
|
56
58
|
"bs58": "^6.0.0",
|
|
57
59
|
"buffer": "^6.0.3"
|