useSolana and useEthereum) for signing messages optimized for mobile platforms.
Chain-specific message signing hooks
These examples copy signatures withexpo-clipboard, and the Solana example encodes signatures with bs58. Install both before running the examples:
npx expo install expo-clipboard
npm install bs58
Solana message signing (useSolana)
import React, { useState } from "react";
import { View, Button, TextInput, Alert, Text, StyleSheet } from "react-native";
import * as Clipboard from "expo-clipboard";
import bs58 from "bs58";
import { useSolana } from "@phantom/react-native-sdk";
function SolanaMessageSigning() {
const { solana } = useSolana();
const [message, setMessage] = useState("Hello from Solana!");
const [isLoading, setIsLoading] = useState(false);
const handleSign = async () => {
if (!message.trim()) {
Alert.alert("Error", "Please enter a message");
return;
}
setIsLoading(true);
try {
// signature is a Uint8Array; encode it before displaying or copying
const { signature } = await solana.signMessage(message);
const encodedSignature = bs58.encode(signature);
Alert.alert(
"Message Signed!",
`Signature: ${encodedSignature.slice(0, 20)}...`,
[
{ text: "Copy", onPress: () => Clipboard.setStringAsync(encodedSignature) },
{ text: "OK" },
]
);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
Alert.alert("Error", `Signing failed: ${errorMessage}`);
} finally {
setIsLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Sign Solana Message</Text>
<TextInput
style={styles.input}
placeholder="Enter message to sign"
value={message}
onChangeText={setMessage}
multiline
/>
<Button
title={isLoading ? "Signing..." : "Sign Message"}
onPress={handleSign}
disabled={isLoading}
/>
</View>
);
}
const styles = StyleSheet.create({
container: { padding: 20, gap: 12 },
title: { fontSize: 18, fontWeight: "600" },
input: { borderWidth: 1, borderColor: "#ccc", borderRadius: 8, padding: 12, minHeight: 80 },
});
Ethereum message signing (useEthereum)
Ethereum methods aren’t available on React Native yet. The React Native SDK connects only through embedded wallets (Google and Apple social login), and EVM support for embedded wallets is coming soon. See Chain support for current availability.
import React, { useState } from "react";
import { View, Button, TextInput, Alert, Text, StyleSheet } from "react-native";
import * as Clipboard from "expo-clipboard";
import { useEthereum } from "@phantom/react-native-sdk";
function EthereumMessageSigning() {
const { ethereum } = useEthereum();
const [message, setMessage] = useState("Hello from Ethereum!");
const [isLoading, setIsLoading] = useState(false);
const handleSignPersonal = async () => {
if (!message.trim()) {
Alert.alert("Error", "Please enter a message");
return;
}
setIsLoading(true);
try {
const accounts = await ethereum.getAccounts();
const signature = await ethereum.signPersonalMessage(message, accounts[0]);
Alert.alert(
"Message Signed!",
`Signature: ${signature.slice(0, 20)}...`,
[
{ text: "Copy", onPress: () => Clipboard.setStringAsync(signature) },
{ text: "OK" },
]
);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
Alert.alert("Error", `Signing failed: ${errorMessage}`);
} finally {
setIsLoading(false);
}
};
const handleSignTypedData = async () => {
setIsLoading(true);
try {
const typedData = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
],
Message: [
{ name: "content", type: "string" },
]
},
primaryType: "Message",
domain: {
name: "My Mobile App",
version: "1",
chainId: 1,
},
message: {
content: message,
}
};
const accounts = await ethereum.getAccounts();
const signature = await ethereum.signTypedData(typedData, accounts[0]);
Alert.alert(
"Typed Data Signed!",
`Signature: ${signature.slice(0, 20)}...`,
[
{ text: "Copy", onPress: () => Clipboard.setStringAsync(signature) },
{ text: "OK" },
]
);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
Alert.alert("Error", `Signing failed: ${errorMessage}`);
} finally {
setIsLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Sign Ethereum Message</Text>
<TextInput
style={styles.input}
placeholder="Enter message to sign"
value={message}
onChangeText={setMessage}
multiline
/>
<View style={styles.buttonContainer}>
<Button
title={isLoading ? "Signing..." : "Sign Personal Message"}
onPress={handleSignPersonal}
disabled={isLoading}
/>
<Button
title={isLoading ? "Signing..." : "Sign Typed Data"}
onPress={handleSignTypedData}
disabled={isLoading}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { padding: 20, gap: 12 },
title: { fontSize: 18, fontWeight: "600" },
input: { borderWidth: 1, borderColor: "#ccc", borderRadius: 8, padding: 12, minHeight: 80 },
buttonContainer: { gap: 8 },
});