Skip to content

Instantly share code, notes, and snippets.

@AlmostEfficient
Last active March 4, 2025 08:01

Revisions

  1. AlmostEfficient revised this gist Jan 18, 2024. 1 changed file with 206 additions and 0 deletions.
    206 changes: 206 additions & 0 deletions create-transaction-quickstart.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,206 @@
    ---
    title: "Create and send a transaction"
    description:
    "This quickstart guide will show you how to build a transaction from scratch
    using the Solana SDK in Javascript."
    keywords:
    - Solana SDK
    - install solana SDK
    - create transaction solana
    - solana send transaction
    - create sdk transaction
    - tutorial
    - intro to solana development
    - blockchain developer
    - blockchain tutorial
    - web3 developer
    ---

    This quickstart guide will show you how to use the Solana Javascript SDK to
    create, sign and send a transaction on the devnet, including environment setup.

    ## What you will learn

    - How to load a local filesystem wallet using the SDK
    - How to interact with custom programs on the devnet
    - How to create instructions that include custom data
    - How to use the SDK to create, sign and send a transaction

    ## Prerequisites

    This guide assumes you've completed [local development setup](./local.md) and
    have a filesystem wallet set up.

    Make sure you have [Node.js](https://nodejs.org/en/) installed. You can check
    this by running `node -v` in your terminal. You should see a version number
    printed out.

    ## Set up your environment

    ### Configure the CLI to use devnet

    We'll be using the devnet for this guide. Set the Solana CLI to use the devnet
    by running:

    ```bash
    solana config set --url devnet
    ```

    Next, run `solana airdrop 2` to get some SOL for the devnet. If this fails,
    reduce the amount by using `solana airdrop 1`. You need less than 0.01 SOL to
    send a transaction, check your balance by running `solana balance`.

    ### Setup a local client

    Start by creating a node project and installing the Solana SDK. Run this in your
    terminal:

    ```bash
    mkdir create-tx
    cd create-tx
    npm init -y
    npm install @solana/web3.js
    ```

    Open the `solana-tx` directory in your favorite code editor.

    ## Connect to the devnet and load a local wallet

    Create a file called `main.js` and add the following code:

    ```js
    const web3 = require("@solana/web3.js");
    const os = require("os");
    const fs = require("fs");
    const path = require("path");

    const CLUSTER = web3.clusterApiUrl("devnet");
    const connection = new web3.Connection(CLUSTER, "confirmed");
    const PROGRAM_ID = new web3.PublicKey(
    "7UCpQWEgiX7nv4sibshx93JfEictrRcgrjhgTqGn77XK",
    );

    const keypairPath = path.join(os.homedir(), ".config", "solana", "id.json");
    let keypair;

    try {
    keypair = web3.Keypair.fromSecretKey(
    Buffer.from(JSON.parse(fs.readFileSync(keypairPath, "utf-8"))),
    );
    } catch (err) {
    console.error("Error while loading the keypair:", err);
    process.exit(1);
    }

    console.log("Local keypair address:", keypair.publicKey.toBase58());
    ```

    This code imports the Solana SDK, creates a connection to the Solana Devnet, and
    loads the keypair from the filesystem wallet. The `PROGRAM_ID` provided is for a
    program deployed on the devnet that echoes back whatever data we send to it.

    Running the script as it is with `node main.js` will print out the address of
    your local keypair.

    ## Create a transaction

    We're now ready to create a transaction. Add this function below your existing
    code:

    ```js
    async function echoProgram(connection, payer, programId) {
    // Format instruction data as a buffer of UTF-8 bytes
    const instructionData = Buffer.from("Hello Solana Devnet");

    const instruction = new web3.TransactionInstruction({
    // An array of addresses that the instruction will read from, or write to
    keys: [
    {
    pubkey: payer.publicKey,
    isSigner: true,
    isWritable: false,
    },
    ],

    // The program we're interacting with
    programId,

    // Instruction data in bytes
    data: instructionData,
    });

    // You can create another instruction here if you want to echo a second time or interact with another program

    // Create a transaction and add the instruction we just defined
    // We can add multiple instructions here that are run sequentially
    const transaction = new web3.Transaction().add(instruction);

    const signature = await web3.sendAndConfirmTransaction(
    connection,
    transaction,
    [payer],
    );

    console.log(
    `You can view your transaction on the Solana Transaction https://explorer.solana.com/tx/${signature}?cluster=devnet`,
    );
    }

    echoProgram(connection, keypair, PROGRAM_ID).catch(console.error);
    ```

    This function creates, signs and sends a transaction to the devnet. The
    transaction contains an instruction to interact with the echo program we defined
    earlier.

    ### Build the instruction

    The first thing we're doing is formatting our instruction data into a buffer of
    UTF-8 bytes. While UTF-8 itself is not "binary", it is a way of converting
    something (like text) into a binary format that can be more efficiently stored
    and transmitted by computer systems. This is called "serialization".

    This is done for a few reasons:

    - Speed: It's more efficient to store and transmit data in bytes
    - Interoperability: Programs written in different languages can interact with
    each other because they all use the same format
    - Uniformity: It's easier to work with data in a consistent format
    - Security: It's more secure to use a consistent format to prevent ambiguity in
    interpretation of the data

    The instruction data is then passed to the `TransactionInstruction` constructor
    along with the program ID and the keypair of the payer. The payer is the account
    that will pay for the transaction fees. In this case, we're using the keypair
    from our local wallet.

    ### Create, sign and send the transaction

    Next, we create a transaction and add the instruction we just defined. We can
    add multiple instructions here that are run sequentially. Finally, we sign and
    send the transaction to the devnet.

    Run this script with `node main.js` and you should see a link to the transaction
    on the Solana Explorer. Scroll down to the bottom and you'll see your message in
    the program instruction logs!

    > Program logged: "Received data: [72, 101, 108, 108, 111, 32, 83, 111, 108, 97, 110, 97, 32, 68, 101, 118, 110, 101, 116]"
    > Program logged: "Echo: Hello Solana Devnet"
    > Program consumed: 6837 of 200000 compute units
    > Program returned success

    ### Congratulations!

    You can now build transactions that take in custom instruction data! The
    majority of blockchain development is interacting with existing programs. You
    can build hundreds of apps that just interact with all the programs already out
    there.

    ## Next steps

    Check out these links to learn more about transactions and programs:

    - [Learn more about the Solana Javascript SDK](../developing/clients/javascript-reference.md)
    - [Check out the web3-examples repo for common transactions](https://github.com/solana-developers/web3-examples)
    - [Learn more about transactions](../developing/programming-model/transactions)
    - [Deploy your own Rust program](./rust.md)
  2. AlmostEfficient created this gist Jan 18, 2024.
    274 changes: 274 additions & 0 deletions cli-sdk-quickstart.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,274 @@
    ---
    title: "CLI & SDK quickstart"
    description:
    "This quickstart guide will show you how to use the CLI and the SDK to send
    SOL."
    keywords:
    - solana cli send transaction
    - send SOL using SDK
    - transfer SOL using CLI
    - set up Solana Javascript SDK
    - set up Solana web3 API
    - tutorial
    - intro to solana development
    - blockchain developer
    - blockchain tutorial
    - web3 developer
    ---

    This quickstart guide will show you how to use the Solana CLI and the Javascript
    SDK to send SOL, including environment setup.

    ## What you will learn

    - How to use the Solana CLI to transfer SOL
    - How to set up the Javascript SDK
    - How to load a local filesystem wallet using the SDK
    - How to use the SDK to transfer SOL

    ## Prerequisites

    This guide assumes you've completed [local development setup](./local.md) and
    have a filesystem wallet with SOL in it. Running `solana config get` should
    output the following:

    ```bash
    $ solana config get
    Config File: /Users/NAME/.config/solana/cli/config.yml
    RPC URL: http://localhost:8899
    WebSocket URL: ws://localhost:8900/ (computed)
    Keypair Path: /Users/NAME/.config/solana/id.json
    Commitment: confirmed
    ```

    Make sure you have `solana-test-validator` running in one terminal window.
    Running `solana balance` in a second window should print out:

    2 SOL

    ## Use the CLI to transfer SOL

    We'll start by transferring SOL from one account to another using the CLI.

    ### Create a new wallet keypair

    You need a recipient address to send SOL to. Create a new keypair and record its
    public key:

    ```bash
    solana-keygen new --no-passphrase --no-outfile
    ```

    The output will contain the address after the text pubkey:.

    ```bash
    pubkey: GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
    ```

    ### Send SOL to the new address

    We'll use the `transfer` command to send 0.05 SOL to the new address.

    ```bash
    # solana transfer <RECIPIENT_ADDRESS> <AMOUNT>
    solana transfer GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV 0.05
    ```

    This will give you an error:

    ```bash
    Error: The recipient address (GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV) is not funded. Add `--allow-unfunded-recipient` to complete the transfer
    ```

    The recipient address has not been "initialized" yet: it has never held any SOL
    and does not have enough for rent, so the Solana network does not know about it
    yet.

    Add the `--allow-unfunded-recipient` flag to the command to send SOL to it:

    ```bash
    solana transfer GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV 0.05 --allow-unfunded-recipient
    ```

    This will output a transaction signature. To view transaction details, you can
    run `solana confirm -v <TRANSACTION_SIGNATURE>`.

    Finally, check the balance of the new address with:

    ```bash
    solana balance GKvqsuNcnwWqPzzuhLmGi4rzzh55FhJtGizkhHaEJqiV
    ```

    You now know how to transfer SOL from one account to another using the CLI!

    For more information on the `transfer` command, you can run
    `solana help transfer` in your terminal.

    ## Using the SDK to transfer SOL

    Transferring SOL using the CLI is impractical for most applications. The Solana
    SDK is the primary tool used for such tasks. We'll use it to build a script that
    transfers SOL from one account to another.

    ### Prerequisites

    Make sure you have [Node.js](https://nodejs.org/en/) installed. You can check
    this by running `node -v` in your terminal. You should see a version number
    printed out.

    ### Setup a local client

    Start by creating a node project and installing the Solana SDK. Run this in your
    terminal:

    ```bash
    mkdir send-sol
    cd send-sol
    npm init -y
    npm install @solana/web3.js
    ```

    ### Connect to file system wallet

    Create a file called `main.js` and add the following code:

    ```js
    const web3 = require("@solana/web3.js");
    const os = require("os");
    const fs = require("fs");
    const path = require("path");

    const CLUSTER = "http://127.0.0.1:8899";
    const connection = new web3.Connection(CLUSTER, "confirmed");
    const recipient = new web3.PublicKey(
    "9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g",
    );
    ```

    This code imports the Solana SDK and creates a connection to the local Solana
    cluster. It also defines the recipient address we'll be sending SOL to, which is
    the address of the faucet on the devnet. You can swap this out for any other
    address you want to send SOL to.

    ### Load the filesystem wallet

    Next, we need to load the keypair from the file system wallet. This is the
    keypair you created when you ran `solana-keygen new` in the local development
    quickstart. Add this code below the previous block:

    ```js
    // Import the existing keypair from the file system wallet
    const keypairPath = path.join(os.homedir(), ".config", "solana", "id.json");
    let keypair;

    try {
    keypair = web3.Keypair.fromSecretKey(
    Buffer.from(JSON.parse(fs.readFileSync(keypairPath, "utf-8"))),
    );
    } catch (err) {
    console.error("Error while loading the keypair:", err);
    process.exit(1);
    }

    console.log("Local keypair address:", keypair.publicKey.toBase58());
    ```

    ### Create the transaction and send it

    Finally, we'll use the built in transfer function to send 0.05 SOL to the
    recipient address.

    ```js
    async function transferSol(connection, payer, recipient) {
    console.log("Transferring 0.05 SOL...");

    // Create a transaction and add a system instruction to transfer SOL
    const transaction = new web3.Transaction().add(
    // This system instruction takes the sender's address, the recipient's address, and the amount to transfer
    web3.SystemProgram.transfer({
    fromPubkey: payer.publicKey,
    toPubkey: recipient,
    lamports: web3.LAMPORTS_PER_SOL * 0.005, // The amount of SOL must be in Lamports, the smallest unit of SOL
    }),
    );

    try {
    // Sign and send the transaction to the local cluster using the keypair
    const signature = await web3.sendAndConfirmTransaction(
    connection,
    transaction,
    [payer],
    );
    console.log(
    "View this transaction at:",
    `https://explorer.solana.com/tx/${signature}?cluster=custom`,
    );

    const newBalance = await connection.getBalance(payer.publicKey);
    console.log("New balance is", newBalance / web3.LAMPORTS_PER_SOL);
    } catch (err) {
    console.error("Error while transferring:", err);
    }
    }

    transferSol(connection, keypair, recipient).catch(console.error);
    ```

    This code creates a transaction with one instruction that transfers 0.05 SOL
    from the keypair's address to the recipient address. It then signs and sends the
    transaction to the local cluster. Finally, it prints out the new balance of the
    keypair's address.

    You can run this script with `node main.js`. You should see the following
    output:

    ```bash
    Local keypair address: 8r97HfVyCprL98Cc1a4QgwAJ7eijqzQwrgDazxdSqLf8
    Transferring 0.05 SOL...
    New balance is 0.90
    ```

    Check out the
    [web3-examples](https://github.com/solana-developers/web3-examples) repo for
    more examples of interacting with Solana programs using the SDK.

    ## Going beyond localhost

    Everything you've done so far has been on your local machine. The wallet
    balances will disappear when you exit the terminal running the
    `solana-test-validator` process.

    You can send SOL on the devnet or the mainnet by changing your RPC URL, pointing
    the script to the a different cluster and running it again.

    Update your CLI and get devnet SOL:

    ```bash
    # This configures your CLI to use the devnet cluster
    solana config set --url devnet
    solana airdrop 2
    ```

    In `main.js`, change the `CLUSTER` variable to `devnet`:

    ```js
    const CLUSTER = web3.clusterApiUrl("devnet");
    ```

    Run the script again:

    ```bash
    node main.js
    ```

    You've now sent SOL on the devnet! Make sure you change the cluster on the
    explorer to devnet to see the transaction.

    ## Next steps

    See the links below to learn more about the CLI and the SDK:

    - [Learn more about the Solana CLI](../cli)
    - [Learn more about the Solana Javascript SDK](../developing/clients/javascript-reference.md)
    - [Check out the web3-examples repo](https://github.com/solana-developers/web3-examples)
    - [Deploy your own token on the devnet with the `spl-token` cli](./token.md)
    173 changes: 173 additions & 0 deletions create-token-quickstart.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,173 @@
    ---
    title: "Create a token"
    description:
    "This quickstart guide will show you how to use the spl-token CLI to create a
    token."
    keywords:
    - create token on solana
    - make coin on solana
    - set up spl-token cli
    - spl-token tutorial
    - intro to solana development
    - blockchain developer
    - blockchain tutorial
    - web3 developer
    ---

    This quickstart guide will show you how to use the `spl-token` CLI to create a
    token on the devnet, mint some tokens, and transfer them to another address.

    ## Prerequisites

    This guide assumes you've completed [local development setup](./local.md) and
    have a filesystem wallet created.

    You'll also need to have `cargo` installed. The recommended way to install it is
    with [rustup](https://www.rust-lang.org/tools/install). You can check if you
    have it installed by running `cargo --version` in a terminal window.

    ### Configure the CLI to use devnet

    We'll be using the devnet for this guide. Set the Solana CLI to use the devnet
    by running:

    ```bash
    solana config set --url devnet
    ```

    Next, run `solana airdrop 2` to get some SOL for the devnet. You only need about
    0.5 SOL to create a token, check your balance by running `solana balance`.

    ## The Solana Program Library

    Tokens on Solana are created using the
    [Token Program](https://spl.solana.com/token), which is part of the Solana
    Program Library - a set of programs maintained by Solana Labs.

    ### How tokens are made

    To create a fungible token on Solana, you interact with the SPL token program to
    create a mint account. The mint account contains the token's metadata, including
    the token's supply and decimals. Think of it like a factory that can mint new
    tokens.

    Users' wallets can't directly own tokens on Solana. For each token, a user has a
    token account. The token account stores the balance of a token and is linked to
    the user's wallet.

    So to create a token and add them into your wallet, you need to:

    1. Create a token mint account
    2. Create a token account for your wallet
    3. Mint tokens into your token account

    Here's a simplified visual representation of this relationship:
    ![Token mint and token account relationship](/img/wallet-token-mint.svg)

    ### Install the spl-token-cli

    The SPL has a CLI tool and a Javascript SDK that lets you interact with the
    on-chain programs. We'll use the CLI tool. Install it by running:

    ```bash
    cargo install spl-token-cli
    ```

    This may take a few minutes to run.

    ### Create a fungible token

    To create fungible token, you'll first need to create a mint account. Run this
    command to interact with the token program:

    ```bash
    spl-token create-token
    ```

    This will give you:

    ```bash
    Creating token FpFppjxbnSwX7kBX9X1K5FZLG1N4qnJxAxj1D7VB7gk9 under program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

    Address: FpFppjxbnSwX7kBX9X1K5FZLG1N4qnJxAxj1D7VB7gk9
    Decimals: 9

    Signature: 382YHasjtx9CCpu55hL9x8s3ZeY77Jmw9RKFd3y7SSf9HXqw7kUToMLQLuaUMf6mMZqs65rBPNaYhmQqwejntaKG
    ```

    "Address" here is the token mint account - it contains the token's metadata and
    can be used to mint new tokens - copy this. You can change the metadata, such as
    the decimal count, later on.

    ### Mint and transfer tokens

    All tokens created by `spl-token` have no supply by default - zero of them
    exist. To mint new tokens, you have to first create a token account to hold
    them. Create it by running:

    ```bash
    # spl-token create-account <token-mint-address>
    spl-token create-account FpFppjxbnSwX7kBX9X1K5FZLG1N4qnJxAxj1D7VB7gk9
    ```

    This creates a new token account for your wallet for the token you just created,
    printing out the address:

    ```bash
    Creating account DkoGBArBHqNfbgdzrCAufe51uvn7SWSnSKEpwDYcU7F2

    Signature: 4HEqkQY3PM1g9XKbpZ6PfKX3i55nGbg2YnfQcdhyB64JMtXPQSyEFCBSUHpSXF2stsRjkQ1caaYofSrVE73VvdWR
    ```

    Next, mint some tokens for yourself by running:

    ```bash
    # spl-token mint <token-mint-address> <amount>
    spl-token mint FpFppjxbnSwX7kBX9X1K5FZLG1N4qnJxAxj1D7VB7gk9 1000
    ```

    This will mint 1000 tokens into the token account you just created for your
    wallet.

    You can now transfer tokens from your wallet to another wallet by running:

    ```bash
    spl-token transfer --fund-recipient <token-mint-address> <amount> <destination-address>
    ```

    You can check the balance of your wallet for any token using:

    ```bash
    spl-token balance <token-mint-address>
    ```

    To view all the token accounts you own and their balances:

    ```bash
    spl-token accounts
    ```

    ## Summary

    Here are all the commands you need to run to create a token and mint it:

    ```bash
    spl-token create-token
    spl-token create-account <token-mint-address>
    spl-token mint <token-mint-address> <amount>
    ```

    And to transfer tokens:

    ```bash
    spl-token transfer --fund-recipient <token-mint-address> <amount> <destination-address>
    ```

    ## Next steps

    You now know how to use the `spl-token` CLI to mint a token. It's possible to do
    this and much more with the `spl-token` Typescript library.

    - [Learn more about the SPL token program, the CLI, and the Typescript library](https://spl.solana.com/token)
    - [Update the metadata of your token, such as the name and symbol](https://docs.metaplex.com/programs/token-metadata/overview)
    - [Create and deploy a Solana Rust program](./rust.md)
    278 changes: 278 additions & 0 deletions dApp-client-quickstart.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,278 @@
    ---
    title: "Create a dApp client"
    description:
    "This quickstart guide will show you how to set up a client that lets anyone
    interact with a custom program on the Solana Devnet"
    keywords:
    - Solana client
    - Nextjs app Solana
    - Create Solana dApp
    - Build Solana client
    - Deploy the Solana dApp scaffold
    - deploy a Solana dApp
    - Solana dApp tutorial
    - intro to Solana development
    ---

    This quickstart guide will show you how to set up a client that lets anyone
    interact with an existing program on the Solana Devnet. We'll use the
    [create-solana-dapp](https://github.com/solana-developers/create-solana-dapp)
    CLI to set up a Next.js app and configure it to send a message to the Echo
    program.

    ## What you will learn

    - How to use `create-solana-dapp` to set up a client
    - Configuring the Solana dApp scaffold
    - Interacting with programs on the devnet
    - Sending instruction data from clients to programs

    ## Prerequisites

    Make sure you have [Node.js](https://nodejs.org/en/) installed. You can check
    that it's available by running `node -v` in your terminal. You should see a
    version number printed out.

    ## Set up the client

    ### The Solana dApp scaffold

    The easiest and quickest way to get started building a web app client is using
    one of the available dApp scaffolds. These are available for Next.js, Vue and
    Svelte. We'll use the Next.js scaffold for this guide.

    Start by setting up the Next.js scaffold using `create-solana-dapp` by running
    this in your terminal:

    ```bash
    npx create-solana-dapp solana-dapp
    ```

    The first time you run this, it will ask you if you want to install
    `create-solana-dapp`. Enter `y` and hit enter. This will install the CLI
    globally on your machine and run it. It may take a few minutes as it will also
    install all the dependencies for the scaffold.

    Open up the `solana-dapp` folder in your code editor and navigate to the `app`
    folder inside it. You can ignore the `program` folder for now. Start the
    template by running `npm run dev` in your terminal. This will start the Next.js
    app on `localhost:3000`.

    ### The wallet adapter

    The [Solana Wallet adapter](https://github.com/solana-labs/wallet-adapter#usage)
    is a library that makes it easy to connect to any wallets on Solana that support
    the official wallet standard. This means you don't need to implement separate
    APIs for different wallets - the wallet adapter will handle that for you.

    Open up `src/contexts/ContextProvider.tsx` in your code editor. You'll find the
    `ContextProvider` component that wraps the entire app, making the wallet adapter
    available to all pages and children components in the app.

    The wallet adapter is initialized with a list of wallets that the user can
    choose from. By default the scaffold uses the `UnsafeWalletAdapter` which is a
    wallet that is only meant for development purposes. Change it to a list of
    wallets that you want to support in your app like this:

    ```tsx
    // Line 3
    import {
    SolflareWalletAdapter,
    } from '@solana/wallet-adapter-wallets';

    ...

    // Line 30
    const wallets = useMemo(
    () => [
    new SolflareWalletAdapter(),
    ],
    [network]
    );
    ```

    This will enable the Solflare wallet in your app as well as any wallets that are
    registered as a standard wallet and installed in the user's browser (such as
    Phantom and Glow).

    ## Interacting with programs

    The scaffold has several components that you can use to interact with programs
    and send transactions. When exploring it, start with just one component and
    stick with it so you don't get overwhelmed.

    ### Set up the `SendEcho` component

    To interact with the echo program using the client, we'll need to send a
    transaction that is signed and funded by the user. Create a file called
    `SendEcho.tsx` in `app/src/components` and add the following code to it:

    ```tsx
    import { useConnection, useWallet } from "@solana/wallet-adapter-react";
    import {
    Transaction,
    TransactionSignature,
    TransactionInstruction,
    PublicKey,
    } from "@solana/web3.js";
    import { FC, useCallback } from "react";
    import { notify } from "../utils/notifications";

    export const SendEcho: FC = () => {
    const { connection } = useConnection();
    const { publicKey, sendTransaction } = useWallet();
    const programId = new PublicKey(
    "7UCpQWEgiX7nv4sibshx93JfEictrRcgrjhgTqGn77XK",
    );

    const onClick = useCallback(async () => {
    // Transaction code will go here
    }, []);

    return (
    <div className="flex flex-row justify-center">
    <div className="relative group items-center">
    <div
    className="m-1 absolute -inset-0.5 bg-gradient-to-r from-indigo-500 to-fuchsia-500
    rounded-lg blur opacity-20 group-hover:opacity-100 transition duration-1000 group-hover:duration-200 animate-tilt"
    ></div>
    <button
    className="group w-60 m-2 btn animate-pulse bg-gradient-to-br from-indigo-500 to-fuchsia-500 hover:from-white hover:to-purple-300 text-black"
    onClick={onClick}
    disabled={!publicKey}
    >
    <div className="hidden group-disabled:block ">
    Wallet not connected
    </div>
    <span className="block group-disabled:hidden">Send Echo</span>
    </button>
    </div>
    </div>
    );
    };
    ```

    This has the same styling and structure as the other transaction components in
    the scaffold. The imports have been updated for this transaction and the
    `programId` of the Echo program has been added.

    To test it, we'll put it in `app/src/views/basics/index.tsx` alongside the other
    basics:

    ```tsx
    import { FC } from "react";
    import { SignMessage } from "../../components/SignMessage";
    import { SendTransaction } from "../../components/SendTransaction";
    import { SendVersionedTransaction } from "../../components/SendVersionedTransaction";
    import { SendEcho } from "../../components/SendEcho";

    export const BasicsView: FC = ({}) => {
    return (
    <div className="md:hero mx-auto p-4">
    <div className="md:hero-content flex flex-col">
    <h1 className="text-center text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-br from-indigo-500 to-fuchsia-500 mt-10 mb-8">
    Basics
    </h1>
    <div className="text-center">
    <SignMessage />
    <SendTransaction />
    <SendVersionedTransaction />
    {/* Added here */}
    <SendEcho />
    </div>
    </div>
    </div>
    );
    };
    ```

    Head over to `localhost:3000/basics` and you'll see the `Send Echo` button. It
    does nothing right now as we haven't added the transaction code.

    ### Create a transaction on the client

    The code for this will be largely the same as the transaction quickstart,
    however, instead of loading a keypair from a file, we'll use the wallet adapter
    to get the user to sign and pay for the transaction.

    Add the following code to the `onClick` function on line 18:

    ```tsx
    const onClick = useCallback(async () => {
    if (!publicKey) {
    notify({ type: "error", message: `Wallet not connected!` });
    console.log("error", `Send Transaction: Wallet not connected!`);
    return;
    }

    let signature: TransactionSignature = "";
    const message = prompt("Enter message for the blockchain:");

    if (!message) {
    notify({ type: "error", message: `No message entered!` });
    console.log("error", `No message entered!`);
    return;
    }

    try {
    // Format the message as bytes
    const messageBytes = Buffer.from(message);

    console.log("Message bytes:", messageBytes);

    const instructions = new TransactionInstruction({
    keys: [{ pubkey: publicKey, isSigner: true, isWritable: false }],
    programId,
    data: messageBytes,
    });

    let latestBlockhash = await connection.getLatestBlockhash();

    const transaction = new Transaction().add(instructions);

    signature = await sendTransaction(transaction, connection);

    await connection.confirmTransaction(
    { signature, ...latestBlockhash },
    "confirmed",
    );

    notify({
    type: "success",
    message: "Transaction successful!",
    txid: signature,
    });
    } catch (error: any) {
    notify({
    type: "error",
    message: `Transaction failed!`,
    description: error?.message,
    txid: signature,
    });
    console.log("error", `Transaction failed! ${error?.message}`, signature);
    return;
    }
    }, [publicKey, notify, connection, sendTransaction]);
    ```

    This asks the user for a message they want to send to the echo program, formats
    it, creates a transaction and prompts the user to approve it via their wallet.

    Head over to the basics page and try it out. You should see a success toast
    message on the bottom left corner on your screen which contains a link to the
    transaction.

    You now know how to create a transaction with custom instruction data via a
    client!

    ## Next steps

    The scaffold is loaded with useful components and utilities that you will find
    useful when building dapps. Check out the `SignMessage.tsx` component to see how
    to sign messages with the wallet adapter, or see the links below to learn more
    about Solana clients:

    - [Read more about the Solana Wallet Adapter in the Scaffold ](https://solana.com/news/solana-scaffold-part-1-wallet-adapter)
    - [Learn more about the Solana Javascript SDK](../developing/clients/javascript-reference.md)
    - [Check out the web3-examples repo for common transactions](https://github.com/solana-developers/web3-examples)
    - [Learn more about transactions](../developing/programming-model/transactions)