young man sitting at laptop

How to Connect to a Solana Wallet Using Phantom in JavaScript

What is Solana

Solana is a top 10 coin by valuation that has been soaring in popularity.

Solana was started by ex-Qualcomm engineers; Qualcomm is a San Diego semiconductor company, and Solana was named after a beach in San Diego.

As a blockchain, Solana aims to deliver fast, cheap, efficient transactions. Solana and Bitcoin both have fees per transaction that can range into the tens of dollars. Solana's are usually closer to pennies.

Interacting with the Solana Network through Phantom

While Solana's smart contracts are coded in Rust, you can interact with the Solana network using JavaScript.

The first step in setting up a Solana payment system is connecting to the user's wallet from within an app.

The biggest wallet provider in Solana is Phantom. This is what we'll be using in this tutorial.

Phantom describes itself as a 'friendly crypto wallet' with a special focus on tokens and NFT's.

For this project I'll also use React, a natural choice for a user-facing app like this.

This app also assumes the user has installed the Phantom browser extension on their device (laptop or mobile). It won't work without it.

If the user has Phantom, they'll only have to login. If they don't, the app will tell the user to install Phantom if they don't have it.

Project Setup

Start by creating a new project. I'll call mine solwallet.

npx create-react-app solwallet

Navigate to the solwallet/src directory, where you'll find App.js, the file we'll be changing.

cd solwallet/src

The JavaScript Code

The React app has several pieces, which combine to make up the app; paste in the code below to interact with the Phantom wallet.

In this case, everything fits within a single App component. If you only have one component in a React app, it will be App - and that's the case here.

There is only one state variable: walletAddress.

There are several UI components: renderConnectedCointainer, renderNotConnectedContainer, and the bottom section of App.

There are also a few functions that do the heavy lifting.

The function connectWallet let the user click to connect their wallet, if they haven't yet.

The function checkIfWalletIsConnected uses the Solana library to fetch the user's wallet address, if they have one.

useEffect here has a React function that runs upon loading. Here, it checks to see if the user's wallet is connected, and then chooses what to display based on that: your address if you are connected, a button to prompt you to connect if you haven't.


const App = () => {
  const [walletAddress,setWalletAddress]=useState(null);

  const renderConnectedContainer = () => { 
	  return (
		  <>
		  <p >{walletAddress}</p>
		  </>
	  )
  }

  const checkIfWalletIsConnected = async () => {
    try {
      const { solana } = window;

      if (solana) {
        if (solana.isPhantom) {
          console.log('Phantom wallet found!');
          const response = await solana.connect({ onlyIfTrusted: true });
          console.log(
          'Connected with Public Key:',
          response.publicKey.toString());
	  setWalletAddress(response.publicKey.toString());
        }
      } else {
        alert('Solana object not found! Get a Phantom Wallet 👻');
      }
    } catch (error) {
      console.error(error);
    }
  };

  const connectWallet=async () => {
  	const { solana } = window;

  	if (solana) {
    		const response = await solana.connect();
    		console.log('Connected with Public Key:', response.publicKey.toString());
    		setWalletAddress(response.publicKey.toString());
  	}
  };

  const renderNotConnectedContainer = () => (
    <button
      className="cta-button connect-wallet-button"
      onClick={connectWallet}
    >
      Connect to Wallet
    </button>
  );

  useEffect(() => {
    if (walletAddress) {
      console.log("got walletAddress");
      console.log(walletAddress);
    }
  }, [walletAddress]);


  useEffect(() => {
    const onLoad = async () => {
      await checkIfWalletIsConnected();
    };
    window.addEventListener('load', onLoad);
    return () => window.removeEventListener('load', onLoad);
  }, []);

  return (
    <div className="App">
      <div className={walletAddress ? "authed-container":"container"}>
        <div className="header-container">
          <p className="header">Wallet Display </p>
          <p style={{color: 'white'}}>This app shows your Solana wallet address.</p>
          <p className="sub-text"></p>
	  {!walletAddress && renderNotConnectedContainer()}
	  {walletAddress && renderConnectedContainer()}
        </div>
      </div>
    </div>
  );
}

export default App;

App User Flow

First the app checks to see it walletAddress is set. The variable walletAddress is set from within the function checkIfWalletIsConnected.

In the function checkIfWalletIsConnected, the app first connects to Solana, through window. If it can connect, and if the user has a wallet address, it sets it to their address.

If there is a wallet address, the app shows it, in the function renderConnectedContainer.

If there isn't a wallet address, the app shows that too, using renderNotConnectedContainer.

Using the Code

You can run this React app with the command:

npm start

You should now see the app start up, and if you have Phantom, you should be prompted for your password. After that, you should see the wallet address displayed.

And that's how you connect to a user wallet using Solana. You can use this as a foundation to build apps and continue from there.