# Solana Wallet Integration for SOL Transactions

## Introduction

In previous years, the Solana blockchain and crypto coin "SOL" have gained a strong reputation for building more modern blockchain technologies apart from Bitcoin and Etherium blockchains, adding more advanced features for this current time like high processing speeds, the Proof of History concept to make transactions before timestamps, and the priority for developers to work on top of a layer for fast development.

In this tutorial, we will learn some basic functionality with the Solana standard wallet. In this case, we will use a web-based Phanton Wallet on the devnet network. With this basic app, you can build an app to send SOL to another Solana wallet.

Then, all wallet interactions use npm @solana packages like Solana, @solana/web3.js, @solana/wallet-adapter-react-ui, and others.

We will use React with Next.js to create a basic layout for the UI rendering component. You can add more functionalities or leave them as a template. All these are referenced in the Solana docs. This tutorial enriched your stack developer with more knowledge of modern blockchain technologies.

## Use Cases

* Users should be able to connect their Solana wallet to the application web extension.
    
* Users can send SOL to another address or user using the Phanton Wallet web extension.
    
* Users can view their current SOL balance.
    
* Users can track SOL once the transaction was made.
    

**Understanding Public and Secret keys in the Phantom Wallet**

When using the Phantom Wallet or interacting with it, it's essential to understand the roles of public and secret keys in making transactions. For our tutorial purposes, we only need the Public Key because sending transactions will be handled by the Phantom Wallet, so why the keys:

* **Public Key:** The Solana wallet's address ID points to the Solana network. You can share it with others to receive SOL tokens or interact with dApps (decentralized apps).
    
* **Secret Key:** This is the most sensitive key you should keep to access and control your funds. It's used to sign transactions and prove ownership of the funds in your wallet. The Phantom wallet securely stores this key and never exposes it to any external applications, including the one you're building.
    

## Setting Up the Environment

### Prerequisites

* Code Editor of your preference I use VS Code
    
* Basic JavaScript
    
* Node.js
    
* Typescript
    
* Code Editor
    
* Basic HTML, and CSS
    

## Instructions

* Setup environment and install dependencies
    
* Initialize project and configure file structure
    

**Frontend**

* Configure Solana connection
    
* Implement wallet integration
    
* Create UI components
    
* Handle transactions
    

**Backend**

* Handle transaction and security
    
* Testing
    

1. Setup environment and install dependencies
    

First, open VS Code:

![Open VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1u5rxcwouegs9zfol4nv.png align="left")

Open VS Code press F1, and select connect to WSL.

![Connect WSL](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kit0j1ty1rh18vu16g1r.png align="left")

* Open the terminal View &gt; terminal
    

![Open Terminal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qpsng0oyc2qeruehjdop.png align="left")

* Follow the same previous instructions from Linux/Mac
    

**Terminal VS Code**

![Terminal VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sqa07kjqxrzhgbhzowq4.png align="left")

Next, make a folder on your PC, like in a Linux/Mac root folder or Windows. Linux/Mac

It's common to place your projects in a Projects directory within your home directory.

```bash
mkdir -p ~/Projects
```

and move to the project's folder by running:

```bash
cd Projects
```

Your projects would then be located in path like: `/home/your-username/Projects/my_project` (Linux) `/Users/your-username/Projects/my_project` (Mac)

**Windows Using Linux subsystem WSL**

* Follows same steps as previous on Linux/Mac
    

## Installing Next.js

Initialize the Next.js project, and ensure you're in the project directory:

```bash
npx create-next-app@latest wallet-app
```

It will ask some questions yes to all except in include:

* Tailwing CSS **NO**,
    
* to App router **NO**,
    
* and import alias (@/\*) NO, so then Next.js built all the folder and files for you including `.env.local` that we will use on next steps.
    

Move into the project directory:

```bash
cd wallet-app
```

Install required dependencies:

```bash
npm install @solana/web3.js @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-wallets
```

This will install the Solana web3.js library and wallet adapter packages necessary for interacting with the Solana blockchain and handling wallet connections.

2. Initialize project and configure file structure, run the following command to test the app:
    

```bash
npm run dev
```

Run it in your browser most of the time [`localhost:3000`](http://localhost:3000)

**Note**: While you are coding the app try to see the results in your [`localhost:3000`](http://localhost:3000) to make sure everything it's working as expected.

We have to do the file structure like the following tree structure:

```bash
wallet-app/
├── README.md
├── next-env.d.ts
├── next.config.mjs
├── package-lock.json
├── package.json
├── public
│   └── solanaLogo.png       # Any public assets go here
├── src
│   ├── components           # Reusable React components
│   ├── pages                # Next.js pages (e.g., index.tsx)
│   └── styles               # CSS/SCSS files
├── tsconfig.json
└── utils                    # Utility functions and scripts
    └── generator-public-data.ts
```

Make a folder in the root of the project called `utils` and create two files inside [`generator-public.data`](http://generator-public.data)`.ts` and `publicKeyGenerator.ts` that will be used later in the future.

```bash
mkdir utils
```

And create the files:

```bash
touch utils/generator-public-data.ts utils/publicKeyGeneratos.ts
```

Write the following script in Javascript and React to `generator-public-data.ts` file:

```javascript
import { Keypair } from "@solana/web3.js";
import * as fs from "fs";
import * as path from "path";

// Define the path to the .env.local file
const envFilePath = path.resolve(__dirname, "../.env.local");

// Function to check if a key exists in the .env.local file
const keyExistsInEnv = (key: string, filePath: string): boolean => {
  if (!fs.existsSync(filePath)) {

    // File doesn't exist, so the key doesn't exist either
    return false; 
  }
  
  const envFileContent = fs.readFileSync(filePath, "utf-8");
  return envFileContent.includes(`${key}=`);
};

// Check if the keys already exist in the .env.local file
const programIdKey = "NEXT_PUBLIC_PROGRAM_ID";
const dataAccountPubKeyKey = "NEXT_PUBLIC_DATA_ACCOUNT_PUBKEY";

const programIdExists = keyExistsInEnv(programIdKey, envFilePath);
const dataAccountPubKeyExists = keyExistsInEnv(dataAccountPubKeyKey, envFilePath);

if (programIdExists && dataAccountPubKeyExists) {
  console.log("Keys already exist in .env.local. No action taken.");
} else {
  // Generate and append only the keys that don't already exist
  let envContent = "";

  if (!programIdExists) {
    const programKeypair = Keypair.generate();
    const programId = programKeypair.publicKey.toBase58();
    envContent += `${programIdKey}=${programId}\n`;
  }

  if (!dataAccountPubKeyExists) {
    const dataAccountKeypair = Keypair.generate();
    const dataAccountPubKey = dataAccountKeypair.publicKey.toBase58();
    envContent += `${dataAccountPubKeyKey}=${dataAccountPubKey}\n`;
  }

  // Append the new content to the .env.local file if necessary
  if (envContent) {
    fs.appendFileSync(envFilePath, envContent.trim());
    console.log("Missing keys generated and saved to .env.local");
  }
}
```

**Explanation:**

This script is an enhanced utility for generating and managing cryptographic keys in your Solana wallet application. It automates generating keys and adequately stores them in the `.env.local` file.

Here's a step-by-step explanation:

**PublicKey:** This is the identification and when somebody transfers funds from. **Data Account Public Key:** This is where you save all related transactions and contract information.

* First, we import the Solana web3 package to get the Keypair function to generate the keys; then, we import the `fs` File System Module to file reading, writing, and manipulation.
    
* Make the `path` module resolves file paths and cross-platform ways.
    
* We define a function `keyExistsInEnv()` to check if any keys are already in the `.env.local` file.
    
* Save constant values to use with the `keyExistsInEnv()` function.
    
* Saves the result of the `keyExitsInEnv()` function to constant programIdExist.
    
* Generate and save the keys if necessary: If the keys exist, no action is taken.
    
* Key generation: if no keys inside the `.env.local` file, the script will generate the keypairs.
    
* Program ID: if the `NEXT_PUBLIC_PROGRAM_ID` is missing, the script will generate the key.
    
* Data Account Public Key: If the key is missing, the script will generate the key.
    
* Appending to `.env.local`: If missing, the new keys are only appended to the `.env.local` file. This ensures that existing keys aren't overwritten and that only the missing ones are generated.
    

Ensure that the `.env.local` is in the root directory so we can follow along.

Then, ensure the `.env.local` is in the directory's root. Next.js usually creates us automatically, and the `.gitignore` files to be ignored will be added there once the project is created from the beginning of the setup project.

It's the most extended script in the app, but it's straightforward, as you can see.

After this, we can generate the keys out of thin air like magic:

Now, run the following command to generate the public keys in the root's project folder:

```bash
npx esrun utils/generator-public-data.ts
```

If everything is working as expected, you will see the message in the terminal:

```bash
Missing keys generated and saved to .env.local
```

Check the `.env.local` in the root's project structure for the generate it public key strings values:

```bash
NEXT_PUBLIC_PROGRAM_ID="YourGeneratedProgramID"
NEXT_PUBLIC_DATA_ACCOUNT_PUBKEY="YourGeneratedDataAccountPubKey"
```

## publicKeyGenerator.ts

```javascript
import {Keypair} from "@solana/web3.js"

const keypair2 = Keypair.generate()

console.log(`The public key 2 is: ${keypair2.publicKey.toBase58()}`)
console.log(`The secret key 2 is: ${keypair2.secretKey}`)
```

## Explanation

This silly, tiny script basically imports the `Keypair` object from the Solana web3 library. Next, it generates a keypair from the `generate()` method of the `Keypair` object and saves it in a keypair variable. The log the result pairs one: it's a `publicKey` of 58 chars and a `secretKey` with an array of numbers; in this tutorial, for testing purposes, don't worry about the `secretKey`. In real life, in the `mainnet` Solana blockchain, you have to save it in another safe place.

We will use this script at a later time in the project.

The next instruction from the program's design is the 'frontend' part. This also includes the backend. It's a small project, but you can modularize more. These are just the basic concepts to grasp.

## Building the components

In the root's folder structure, expand `src` and pages, and you will see two files: `_app.tsx` and `index.tsx` erase all content from it, and we will implement the following code into those files:

Next.js main entry point app `_app.tsx`

## \_app.tsx

```javascript
import '../styles/globals.css'

function MyApp({ Component, pagePros}) {
  return <Component {...pagePros} />
}

export default MyApp
```

This file includes global CSS to render the appropriate component for the current route.

The main page of your application `index.tsx`

## index.tsx

```javascript
import { NextPage } from "next"
import styles from '../styles/Home.module.css'
import { AppBar } from "@/components/AppBar"
import Head from "next/head"
import WalletContextProvider from "@/components/WalletContextProvider"
import { BalanceDisplay } from "@/components/BalanceDisplay"
import { InputFormWallet } from "@/components/InputFormWallet"


const Home: NextPage = (props) => {
  return (
    <div className={styles.App}>
      <Head>
        <title>Wallet-Adapter Example</title>
        <meta
          name="description"
          content="Wallet-Adapter Example"
        />
      </Head>
      <WalletContextProvider>
        <AppBar />
        <div className={styles.AppBody}>
          <BalanceDisplay />
          <InputFormWallet />
        </div>
      </WalletContextProvider>
    </div>
  )
}

export default Home;
```

This is your application's main page. It integrates all the components to display a functional UI for interacting with Solana wallets and features. The `Home` component renders the `AppBar`, `BalanceDisplay`, and 'InputFormWallet' components, all wrapped inside the `WalletContextProvider`.

## Connect Your Wallet

Before diving into the technical steps, ensure you have the Phantom wallet installed and set up. Phantom is a popular Solana wallet that you'll use to interact with the Solana blockchain

## How to open and Set Up Phantom Wallet:

1. Visit the [Phatom Wallet Website](https://phantom.app/) and download the extension for you preferred browser.
    
2. Follow the on-screen instructions to create a new wallet or import an existing one.
    
3. Once set up, open the Phantm wallet extension and ensure it is connected to the Solana network; in the upper left side, click on config and follow preferences, and then move to `devnet`.
    

In the Phantom wallet, you have your own public key where you receive tokens. In this case, test tokens are not real. Once you open again your Phantom Solana wallet in the upper right corner, once you connect and enter the password, then click on the button and copy that public key address. In order to have some test tokens, go to [Solana Faucet](https://faucet.solana.com/) to get some tokens to test paste your public key there and get some tokens.

Remember, you can send these new test tokens to another public key address for testing purposes. That's the reason we did the previous script to generate a public key address, as well as a secret one, but we won't use it in this project because we are using Phantom wallet, which has its own secret key.

In Chrome, you will see the extension jigsaw symbol "not the movie" :smile: in the upper right corner. Open it and pin the "Phantom wallet" extension to the main bar so that the next time you enter, it's your sight right away.

## UI Components and Connection to Wallet

Before we further create a new folder in the src folder:

```bash
mkdir src/components
```

Inside it, let's add the following files using this command:

```bash
touch src/components/AppBar.tsx src/components/InputFormWallet.tsx src/components/WalletContextProvider.tsx
```

## AppBar.tsx

This component shows the application's top navigation bar, which includes a logo, title, and wallet connection button.

```javascript
import { FC } from "react";
import styles from '../styles/Home.module.css'
import Image from "next/image";
import dynamic from "next/dynamic";
const WalletMultiButton = dynamic(() => import('@solana/wallet-adapter-react-ui').then(mod => mod.WalletMultiButton), { ssr: false });


export const AppBar: FC = () => {
    return(
        <div className={styles.AppHeader}>
            <Image src="/solanaLogo.png" height={30} width={200} alt="logo-image"/>
            <span>Wallet-Adapter Example</span>
            <WalletMultiButton />
        </div>
    )
}
```

As always, test the result in [`localhost:3000`](http://localhost:3000) to see the desired behavior.

The component imports the `WalletMultiButton` dynamically, which is used to connect to various Solana wallets. This button will allow users to connect their wallets to the application. The `styles` object is imported from the `Home.module.css` file, which provides CSS styling for the component. The logo is rendered using the Next.js `image` component for optimized image loading.

Copy this image from your browser or download it to place in `wallet-app/public/solanaLogo.png`

![Solana Logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64y15luybaw2ohcaawep.png align="left")

## BalanceDisplay.tsx

```javascript
import { useConnection, useWallet } from "@solana/wallet-adapter-react"
import { LAMPORTS_PER_SOL } from "@solana/web3.js"
import { FC, useEffect, useState } from 'react'

export const BalanceDisplay: FC = () => {
    const [balance, setBalance] = useState(0);
    const { connection } = useConnection();
    const { publicKey } = useWallet();

    useEffect(() => {
        if (!connection || !publicKey) {
            return;
        }

        connection.onAccountChange(
            publicKey,
            updatedAccountInfo => {
                setBalance(updatedAccountInfo.lamports / LAMPORTS_PER_SOL)
            },
            "confirmed",
        );

        connection.getAccountInfo(publicKey).then(info => {
            setBalance(info.lamports);
        });
    }, [connection, publicKey]);

    return(
        <div>
            <p>{publicKey ? `Balance ${balance / LAMPORTS_PER_SOL}` : ""} </p>
        </div>
    )
}
```

* Displays the balance of SOL (Solana) tokens in the connected wallet in the UI.
    
* Imports all hooks required to interact with Solana wallets, like `useConnection` and `useWallet`.
    
* `LAMPORTS_PER_SOL` is a constant from `@solana/web3.js` representing the number of lamports (the smallest unit of SOL) per SOL (1 SOL = 1,000,000,000 lamports).
    
* `FC` stands for Function component, a type in React. `useEffect` and `useState` are Reach hooks for managing side effects and component state.
    
* `useState(0)` initializes a state variable `balance` with a value of `0`. -`useConnection` provides access to the `connection` object, which is used to interact with the Solana blockchain.
    
* `useWallet` provides the `publicKey` of the connected wallet.
    
* The 'useEffect' hook runs the code inside whenever 'connection' or 'publicKey' changes.
    
* If either `connection` or `publicKey` is unavailable, the function exits early `return`.
    
* `connection.onAccountChange` is an event listener that listens for changes in the account associated with `publicKey`. When the account changes, it updates the `balance` state with the new balance (converted from imports to SOL).
    
* `connection.getAccountInfo` fetches the account information for `publicKey` and updates the `balance` state with the initial balance. Lastly, it's the return to render the content's component.
    

## InputFormWallet.tsx

This file is the body of the page where you see all the functionality to interact with the external Phantom wallet, in this case, with user inputs.

```javascript
import { useConnection, useWallet } from "@solana/wallet-adapter-react"
import React, { FC, useState } from 'react'
import * as web3 from "@solana/web3.js"
import styles from '../styles/Home.module.css'

export const InputFormWallet: FC = () => {
    const [amount, setAmount] = useState<string>("")
    const [recipient, setRecipient] = useState<string>("")
    const { connection } = useConnection()
    const { publicKey, sendTransaction } = useWallet()
    const [transactionLink, setTransactionLink] = useState<string>("")

    const handleAmountChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setAmount(event.target.value)
    }

    const handleRecipientChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setRecipient(event.target.value)
    }

    const handleSubmit = async (event: React.FormEvent) => {
        event.preventDefault()

        if (!connection || !publicKey) {
            console.error("Connection or publickey is not available.")
            return
        }

        try {
            const lamports = parseFloat(amount) * web3.LAMPORTS_PER_SOL
            const recipientPubKey = new web3.PublicKey(recipient)
            const transaction = new web3.Transaction()

            const sendSolInstruction = web3.SystemProgram.transfer({
                fromPubkey: publicKey,
                toPubkey: recipientPubKey,
                lamports,
            })

            transaction.add(sendSolInstruction)


            const signature = await sendTransaction(transaction, connection)
            const explorerUrl = `https://explorer.solana.com/tx/${signature}?cluster=devnet`
            setTransactionLink(explorerUrl)

        } catch (error) {
            console.error("Transaction failed:", error)
        }
    }

    return (
        <div className={styles.AppBody}>
            <form onSubmit={handleSubmit} className={styles.form}>
                <p>Amount (in SOL) to send:</p>
                <input
                    type="text"
                    value={amount}
                    onChange={handleAmountChange}
                    placeholder="Enter amount"
                    className={`${styles.input} ${styles.formField}`}
                />
                <br />
                <p>Send SOL to:</p>
                <input
                    type="text"
                    value={recipient}
                    onChange={handleRecipientChange}
                    placeholder="Enter recipient address"
                    className={`${styles.input} ${styles.formField}`}
                />
                <br />
                {transactionLink && (
                    <a 
                    href={transactionLink} 
                    target="_blank"
                    className={styles.transactionLink}
                    >
                        Check transaction at Solana Explorer
                    </a>

                )}
                <br />
                <button type="submit" className={`${styles.input} ${styles.formField}`}>Send SOL</button>
            </form>

        </div>
    )
}
```

This is a long explanation with all the steps included in each part's file to fully understand the process of handling transactions.

## Imports

* `useConnection` and `useWallet` are hooks from `@solana/wallet-adapter-react` that allow users to interact with Solana's blockchain and use their wallets.
    
* `React` and `useState`: React imports for building components and managing state.
    
* `web3`: Solana's library to handle blockchain interactions.
    

## Component Definition

* `amount` and `recipient`: State variables to store the amount of SOL to send and the recipient's address.
    
* `connection`: Provides the connection to the Solana blockchain.
    
* `publicKey`: The user's public key from the wallet.
    
* `sendTransaction`: Function to send a transaction to the Solana blockchain.
    
* `transationLink`: State variable to store the URL transaction URL on Solana Explorer.
    

## Handlers

Then, the `handleAmountChange` function calculates the `imports` (these ones are like satoshi in Bitcoin) or something similar from `amount` to convert SOL to imports (the smallest unit of SOL). So far, so good.

Next is the `handleRecipientChange` function, which updates the `recipient` state when the user types the recipient address input field.

## Form Submission

In the beginning, we used the `handleSubmit` function to handle form submissions, which has the transaction functionality to check if the connection and public key exist.

After that, we used our beloved `try-catch` block for better debugging practices. We placed all the logic inside the try and initialized the constant variables.

Convert `lamports` from the `amount` state variable to `lamport` (the smallest unit of SOL). Next, we create the `recipientPubKey` to convert the recipient address to a `PublicKey` object and save it to a constant variable `transaction` to construct a new transaction object.

Here, we use a helper function from the 'w3' Solana library to transfer some SOL and chain with the transfer method with the address from the public key and to the recipient address public key. All of these are saved in the `sendSolIntruction` constant variable.

Then, execute the instructions with `sendsolInstructions`, chaining the method 'add' from `transaction` constant variable.

To check if the transaction was successful and if it didn't catch any errors in the process. In blockchain operations in most cryptos, we see that process checking the result of the transaction, the `tx`, the transaction validation or signature, which is a long string of alphanumeric values.

Give the arguments 'transaction' and 'connection' to the `sendTransaction` function from Solana web3. This asynchronous operation saves to a constant variable, `signature`. Now that we have our `signature`, we save it to show the result of building a URL, which we call a variable `explorerUrl`. Set the `explorerUrl` as argument in the `setTransactionLink` state hook.

## Rendering

* Form: a form that triggers 'handleSubmit' on submission.
    
* Amount Input: Field for entering the amount of SOL to send.
    
* Recipient Input: Field for entering the recipient's public address or address to send the SOL tokens.
    
* Submit Button: Button to submit the form and send SOL.
    

This file has all the app's main logic. That's why the explanation took centuries.

## WalletContextProvider

```javascript
import { FC, ReactNode, useMemo } from "react";
import {
    ConnectionProvider,
    WalletProvider,
} from "@solana/wallet-adapter-react"
import { WalletModalProvider} from "@solana/wallet-adapter-react-ui"
import * as web3 from "@solana/web3.js";
require("@solana/wallet-adapter-react-ui/styles.css")

const WalletContextProvider: FC<{ children: ReactNode }> = ({ children }) => {
    const endpoint = web3.clusterApiUrl("devnet");
    const wallets = useMemo(() => [], [])
    
    return (
      <ConnectionProvider endpoint={endpoint}>
        <WalletProvider wallets={wallets}>
          <WalletModalProvider>{children}</WalletModalProvider>
        </WalletProvider>
      </ConnectionProvider>
    );
  };

export default WalletContextProvider;
```

This code file integrates the Solana wallet functionality into our React Next application. It ensures our app can connect to the Solana blockchain and interact with various Solana wallets.

## Imports

* `FC` and `ReactNode`: Typescript types for defining functional components and their children.
    
* `useMemo`: A React hook for memoizing(not repeating, speed up) values to optimize performance.
    
* `ConnectionProvider`, `WalletProvider`: Providers from `@solana/wallet-adapter-react` to handle Solana blockchain connections and wallet interactions.
    
* `WalletModalProvider`: Provides a modal UI for wallet selection from `@solana/wallet-adapter-react-ui`.
    
* `web3`: Solana library for interacting with the blockchain.
    
* `require("@solana/wallet-adapter-react-ui/styles.css")`: Imports the default styles for the wallet UI components.
    

## Explanation

The `WalletContextProvider` is A functional component that takes `children` as a prop. Those children represent the nested components that this provider will wrap.

Next, to interact with the blockchain, call the `devnet` Solana blockchain from the `clusterApiUrl` function from the `web3` library. If it were a real transaction, it has to be the `mainnet` blockchain.

Another variable here is `wallets`, a memoized empty array—adapters to specify which wallets your application supports.

## Rendering

* `ConnectionProvider`: Wraps the application and connects to the Solana blockchain. It takes the `endpoint` as a prop.
    
* `WalletProvider`: Provides wallet functionality and context to the components. It uses the `wallets` array, eventually containing the wallet adapters. The `children` Represent the components nested inside `WalletContextProvider`, which will have access to the Solana connection and wallet functionality.
    

Finally, export the component.

## Style the page's body:

In the file structure in your VS Code panel or your code of choice, localize the folder: `src/styles` and then open `global.css` and erase all the content and place this one standard CSS code:

```css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}
```

Do the same with the following file in `src/styles` and the open `Home.module.css` erase all and copy this code:

```css
.App {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  text-align: left;
  background-color: #282c34;
}

.AppHeader {
  height: 90px;
  display: flex;
  background-color: black;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  font-size: 50px;
  color: white;
  padding-left: 20px;
  padding-right: 20px;
  flex-wrap: wrap;
}

.AppBody {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  font-size: calc(10px + 2vmin);
  color: white;
  padding-top: 50px;
}

.form {
  display: flex;
  flex-direction: column;
  align-items: center;
  border: 1px solid #ccc;
  border-radius: 8px;
  padding: 20px;
  background-color: #333;
}

.input {
  background: #f2f2f2;
  padding: 10px;
  width: 100%;
  max-width: 300px;
  border-radius:  4px;
  border: 1px solid #ccc;
  font-size: 16px;
}

.formField {
  margin: 10px 0;
  width: 100%;
  transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.formField:hover {
  border-color: #0070f3;
  box-shadow: 0 0 5px rgba(0, 122, 243, 0.5);
}

.formButton {
  margin: 10px 0;
  padding: 10px 20px;
  font-size: 16px;
  border: none;
  border-radius: 4px;
  background-color: #0070f3;
  color: #fff;
  cursor: pointer;

}


.transactionLink {
  color: #61dafb;
  text-decoration: none;
  margin-top: 5px;
  font-size: 20px;
  transition: color 0.3s ease;
}
.transactionLink:hover {
  color: #21a1f1;
}
```

All the previous CSS files were to style the body and buttons of the main app's index.tsx\` file.

## Testing

* Check results [`localhost:3000`](http://localhost:3000) in your favorite browser.
    

![UI and Phantom Wallet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmsorrw36ufu8eyzdbzy.png align="left")

Now we have to connect to Phantom wallet:

![Connect Phantom Wallet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ucyhvt3pgyusd9b2abwi.png align="left")

In the upper right corner, you will see the Phantom Wallet public key:

![Balance Publickey Phantom wallet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5nyca8zcrv13gzxdm6o.png align="left")

Now, let's do the main work of this project to send SOL(solana tokens) test tokens as we are using `devnet` blockchain not real.

\-First, input some SOL token to send, in this case, just 0.1:

* Remember the file that we did earlier in the project: at `src/utils/publicKeyGenerator.ts`, open another terminal with this shortcut in Windows: `Ctrl+Shift+` or in Mac `Cmd +` press simultaneously, and you will see another terminal window to work while the server [`localhost:3000`](http://localhost:3000) it's working.
    
* In that terminal type this command:
    

```bash
cd Projects/wallet-app
```

And then, also type this command:

```bash
npx esrun utils/publicKeyGenerator.ts
```

You will see his result in the terminal console:

![Generated PublicKey Address](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2l9x52aiwi86hjwl697.png align="left")

Underneath the public key, you see the secret key and a warning message from `punny` module. For now, just focus on the public key. Those are warnings that once you have to deploy, you will clean it. There is nothing to worry about for now.

Copy Windows `Ctrl + c` Mac `Cmd + c` and paste in the the input "Send SOL to:

![Paste Solana Address](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yocjiuja5ue15icdf7w.png align="left")

After that, send the transaction using are UI to connect to Phantom wallet:

![Press send button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/auvlsfen6thorq0fb0d7.png align="left")

That precious action will open the 'Phantom Wallet', and you will see too some warning messages. Don't worry about those since this is testing in real life you have to clean it. Just click on the 'Confirm' button.

![Phantom Wallet window transaction](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wiv6mfjkbu7kz0xsgd3h.png align="left")

The 'Phantom' window disappears after that, and you will see a blue message between the address we sent the tokens for and the **Send SOL button**:

![Solana transaction tx](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iknjiklg5mcrp8q6myn5.png align="left")

That action will open a new window, the 'Solana Explorer'. It's a web page where you can see your transaction results in action with all the information like:

* Signature
    
* Result
    
* Timestamp
    
* Confirmation Status
    
* Number of confirmations
    

With, all that information, you already know if the transaction was made or not. Remember that this the 'Devnet'; for testing in production app we have to work on 'Mainnet' blockchain.

Back to our UI window, you can see your remaining SOL's balance.

It was a long tutorial please take your time to do it ufffff.

## Summary

This project tutorial explains how to create a simple Solana wallet app using React, TypeScript, and the Solana Web3.js library. The app allows user to connect their wallets, display their SOL balance, and send transitions to other Solana addresses. Key components like `BalanceDisplay`, `InputFormWallet`, and `WalletContextProvider` are covered, along with the necessary imports, state management, and form handling.

The app's styling is also provided to ensure a smooth user interface.

I used all the references from Solana's Official web page. I added some more functionality scripts so you can be comfortable working with this project tutorial.

## Conclusion

By following this project tutorial, you've taken the first step toward building decentralized applications on the Solana blockchain. This basic Solana wallet app demonstrates how to connect to a Solana wallet, display the user's balance, and send transactions using React and TypeScript. The integration with Solana Web3.js introduces essential blockchain interactions, offering a practical introduction to working with decentralized finance(DeFi) and Web3 technologies.

Download the project at: [Github Wallet-App](https://github.com/ivansing/solana/tree/main/wallet-app)

## References

* [Solana docs](https://solana.com/es/docs)
    
* [Solana Official Page](https://solana.com/es)
    
* [Solana Interact with Wallets](https://solana.com/es/developers/courses/intro-to-solana/interact-with-wallets)
    

## About the Author

Ivan Duarte is a backend developer with experience working freelance. He is passionate about web development and artificial intelligence and enjoys sharing their knowledge through tutorials and articles. Follow me on [X](https://x.com/ldway27), [Github](https://github.com/ivansing), and [LinkedIn](https://www.linkedin.com/in/lance-dev/) for more insights and updates.
