useSolana and useEthereum) for signing and sending transactions optimized for mobile platforms.
Chain-specific transaction hooks
Solana transactions (useSolana)
Copy
Ask AI
import React from "react";
import { View, Button, Alert } from "react-native";
import { useSolana } from "@phantom/react-native-sdk";
function SolanaTransactions() {
const { solana } = useSolana();
const sendTransaction = async () => {
try {
// Sign and send transaction
const result = await solana.signAndSendTransaction(transaction);
Alert.alert("Success", `Transaction sent: ${result.hash}`);
} catch (error) {
Alert.alert("Error", `Transaction failed: ${error.message}`);
}
};
const signOnly = async () => {
try {
// Just sign (without sending)
const signedTx = await solana.signTransaction(transaction);
Alert.alert("Success", "Transaction signed!");
} catch (error) {
Alert.alert("Error", `Signing failed: ${error.message}`);
}
};
return (
<View style={{ padding: 20 }}>
<Button title="Send Transaction" onPress={sendTransaction} />
<Button title="Sign Only" onPress={signOnly} />
</View>
);
}
Ethereum transactions (useEthereum)
Copy
Ask AI
import React from "react";
import { View, Button, Alert } from "react-native";
import { useEthereum } from "@phantom/react-native-sdk";
function EthereumTransactions() {
const { ethereum } = useEthereum();
const sendTransaction = async () => {
try {
const result = await ethereum.sendTransaction({
to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
value: "1000000000000000000", // 1 ETH in wei
gas: "21000",
});
Alert.alert("Success", `ETH sent: ${result.hash}`);
} catch (error) {
Alert.alert("Error", `Transaction failed: ${error.message}`);
}
};
return (
<View style={{ padding: 20 }}>
<Button title="Send ETH" onPress={sendTransaction} />
</View>
);
}
Complete mobile examples
Sequential transactions for embedded wallets: When using embedded wallets with Phantom Connect, bundled or parallel transaction execution (such as Jito bundles) isn’t supported. Each transaction must be submitted individually and confirmed before the next can be sent. This is required for spending limit policy enforcement, as the backend must simulate each transaction independently to accurately calculate spending limits.
Solana transaction with mobile UI
Copy
Ask AI
import React, { useState } from "react";
import { View, Button, TextInput, Alert, Text, StyleSheet } from "react-native";
import { useSolana } from "@phantom/react-native-sdk";
import { Transaction, SystemProgram, PublicKey, LAMPORTS_PER_SOL, Connection } from "@solana/web3.js";
function SolanaMobileTransfer() {
const { solana } = useSolana();
const [recipient, setRecipient] = useState("");
const [amount, setAmount] = useState("0.001");
const [isLoading, setIsLoading] = useState(false);
const sendSOL = async () => {
if (!recipient || !amount) {
Alert.alert("Error", "Please fill in all fields");
return;
}
setIsLoading(true);
try {
// Get connection and recent blockhash
const connection = new Connection("https://api.mainnet-beta.solana.com");
const { blockhash } = await connection.getLatestBlockhash();
const fromAddress = await solana.getPublicKey();
const transferInstruction = SystemProgram.transfer({
fromPubkey: new PublicKey(fromAddress),
toPubkey: new PublicKey(recipient),
lamports: parseFloat(amount) * LAMPORTS_PER_SOL,
});
const transaction = new Transaction({
recentBlockhash: blockhash,
feePayer: new PublicKey(fromAddress),
}).add(transferInstruction);
const result = await solana.signAndSendTransaction(transaction);
Alert.alert(
"Success!",
`Sent ${amount} SOL\nTransaction: ${result.hash}`,
[{ text: "OK" }]
);
} catch (error) {
Alert.alert("Error", `Failed to send SOL: ${error.message}`);
} finally {
setIsLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Send Solana</Text>
<TextInput
style={styles.input}
placeholder="Recipient Address"
value={recipient}
onChangeText={setRecipient}
multiline
/>
<TextInput
style={styles.input}
placeholder="Amount (SOL)"
value={amount}
onChangeText={setAmount}
keyboardType="decimal-pad"
/>
<Button
title={isLoading ? "Sending..." : "Send SOL"}
onPress={sendSOL}
disabled={isLoading}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
gap: 15,
},
title: {
fontSize: 20,
fontWeight: "bold",
marginBottom: 10,
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 12,
fontSize: 16,
},
});
Ethereum transaction with mobile UI
Copy
Ask AI
import React, { useState } from "react";
import { View, Button, TextInput, Alert, Text, StyleSheet } from "react-native";
import { useEthereum } from "@phantom/react-native-sdk";
function EthereumMobileTransfer() {
const { ethereum } = useEthereum();
const [recipient, setRecipient] = useState("");
const [amount, setAmount] = useState("0.001");
const [isLoading, setIsLoading] = useState(false);
const sendETH = async () => {
if (!recipient || !amount) {
Alert.alert("Error", "Please fill in all fields");
return;
}
setIsLoading(true);
try {
const weiAmount = (parseFloat(amount) * 1e18).toString(); // Convert ETH to wei
const result = await ethereum.sendTransaction({
to: recipient,
value: weiAmount,
gas: "21000",
});
Alert.alert(
"Success!",
`Sent ${amount} ETH\nTransaction: ${result.hash}`,
[{ text: "OK" }]
);
} catch (error) {
Alert.alert("Error", `Failed to send ETH: ${error.message}`);
} finally {
setIsLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Send Ethereum</Text>
<TextInput
style={styles.input}
placeholder="Recipient Address (0x...)"
value={recipient}
onChangeText={setRecipient}
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholder="Amount (ETH)"
value={amount}
onChangeText={setAmount}
keyboardType="decimal-pad"
/>
<Button
title={isLoading ? "Sending..." : "Send ETH"}
onPress={sendETH}
disabled={isLoading}
/>
</View>
);
}