Skip to main content
The Phantom Connect React Native SDK provides chain-specific hooks (useSolana and useEthereum) for signing messages optimized for mobile platforms.

Chain-specific message signing hooks

Solana message signing (useSolana)

import React, { useState } from "react";
import { View, Button, TextInput, Alert, Text, StyleSheet } from "react-native";
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 {
      const signature = await solana.signMessage(message);
      Alert.alert(
        "Message Signed!",
        `Signature: ${signature.signature.slice(0, 20)}...`,
        [
          { text: "Copy", onPress: () => Clipboard.setString(signature.signature) },
          { text: "OK" },
        ]
      );
    } catch (error) {
      Alert.alert("Error", `Signing failed: ${error.message}`);
    } 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>
  );
}

Ethereum message signing (useEthereum)

import React, { useState } from "react";
import { View, Button, TextInput, Alert, Text, StyleSheet } from "react-native";
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.signature.slice(0, 20)}...`,
        [
          { text: "Copy", onPress: () => Clipboard.setString(signature.signature) },
          { text: "OK" },
        ]
      );
    } catch (error) {
      Alert.alert("Error", `Signing failed: ${error.message}`);
    } 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.signature.slice(0, 20)}...`,
        [
          { text: "Copy", onPress: () => Clipboard.setString(signature.signature) },
          { text: "OK" },
        ]
      );
    } catch (error) {
      Alert.alert("Error", `Signing failed: ${error.message}`);
    } 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>
  );
}