Last active
March 4, 2025 08:01
Revisions
-
AlmostEfficient revised this gist
Jan 18, 2024 . 1 changed file with 206 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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) -
AlmostEfficient created this gist
Jan 18, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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:  ### 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) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal 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)