# Table of Contents - [Learn how the Solana blockchain works | Solana](#learn-how-the-solana-blockchain-works-solana) - [Core Concepts | Solana](#core-concepts-solana) - [Transaction Fees | Solana](#transaction-fees-solana) - [Program-Derived Address | Solana](#program-derived-address-solana) - [Tokens on Solana | Solana](#tokens-on-solana-solana) - [Cross Program Invocation | Solana](#cross-program-invocation-solana) - [Rust SDK for Solana | Solana](#rust-sdk-for-solana-solana) - [Transactions | Solana](#transactions-solana) - [Accounts | Solana](#accounts-solana) - [Frontend | Solana](#frontend-solana) - [Install the Solana CLI and Anchor with one command | Solana](#install-the-solana-cli-and-anchor-with-one-command-solana) - [Programs | Solana](#programs-solana) - [Quick Start | Solana](#quick-start-solana) - [Payments | Solana](#payments-solana) - [Solana RPC Methods: HTTP & Websockets | Solana](#solana-rpc-methods-http-websockets-solana) - [Clusters and Public RPC Endpoints | Solana](#clusters-and-public-rpc-endpoints-solana) - [Tokens on Solana | Solana](#tokens-on-solana-solana) - [Instructions | Solana](#instructions-solana) - [Cross Program Invocation | Solana](#cross-program-invocation-solana) - [Staking on Solana | Solana](#staking-on-solana-solana) - [Solana Gaming SDKs | Solana](#solana-gaming-sdks-solana) - [How Payments Work on Solana | Solana](#how-payments-work-on-solana-solana) - [Common JSON Data Structures for Solana RPC Methods | Solana](#common-json-data-structures-for-solana-rpc-methods-solana) - [Install the dependencies necessary to develop with Solana | Solana](#install-the-dependencies-necessary-to-develop-with-solana-solana) - [SPL Token Basics | Solana](#spl-token-basics-solana) - [@solana/client | Solana](#-solana-client-solana) - [JavaScript/TypeScript SDK for Solana | Solana](#javascript-typescript-sdk-for-solana-solana) - [Reading from Network | Solana](#reading-from-network-solana) - [Solana RPC HTTP Methods | Solana](#solana-rpc-http-methods-solana) - [Interacting with Solana | Solana](#interacting-with-solana-solana) - [Introductory commands for getting started on the Solana CLI | Solana](#introductory-commands-for-getting-started-on-the-solana-cli-solana) - [Extensions | Solana](#extensions-solana) - [Writing to the Network | Solana](#writing-to-the-network-solana) - [@solana/react-hooks | Solana](#-solana-react-hooks-solana) - [Introductory commands for getting started on the Anchor CLI | Solana](#introductory-commands-for-getting-started-on-the-anchor-cli-solana) - [Send Payments | Solana](#send-payments-solana) - [getLatestBlockhash RPC Method | Solana](#getlatestblockhash-rpc-method-solana) - [getAccountInfo RPC Method | Solana](#getaccountinfo-rpc-method-solana) - [Solana wallet integration with Next.js and @solana/react-hooks | Solana](#solana-wallet-integration-with-next-js-and-solana-react-hooks-solana) - [Developing Programs in Rust | Solana](#developing-programs-in-rust-solana) - [@solana/web3-compat | Solana](#-solana-web3-compat-solana) - [Deploy Your First Solana Program | Solana](#deploy-your-first-solana-program-solana) - [Deploying Programs | Solana](#deploying-programs-solana) - [Introductory commands for getting started on the Surfpool CLI | Solana](#introductory-commands-for-getting-started-on-the-surfpool-cli-solana) - [Basic Payment | Solana](#basic-payment-solana) - [Limitations | Solana](#limitations-solana) - [Payment Processing | Solana](#payment-processing-solana) - [Verifying Programs | Solana](#verifying-programs-solana) - [Payment with Memo | Solana](#payment-with-memo-solana) - [getTransaction RPC Method | Solana](#gettransaction-rpc-method-solana) - [getBalance RPC Method | Solana](#getbalance-rpc-method-solana) - [Verify Address | Solana](#verify-address-solana) - [Agentic Payments | Solana](#agentic-payments-solana) - [Accept Payments | Solana](#accept-payments-solana) - [Program Derived Address | Solana](#program-derived-address-solana) - [Stake Accounts | Solana](#stake-accounts-solana) - [Stake Programming | Solana](#stake-programming-solana) - [Go SDK for Solana | Solana](#go-sdk-for-solana-solana) - [Python SDK for Solana | Solana](#python-sdk-for-solana-solana) - [Java SDK for Solana | Solana](#java-sdk-for-solana-solana) - [Fee Abstraction | Solana](#fee-abstraction-solana) - [Create a Token Mint | Solana](#create-a-token-mint-solana) - [Sync Native | Solana](#sync-native-solana) - [Mint Tokens | Solana](#mint-tokens-solana) - [Freeze Account | Solana](#freeze-account-solana) - [Close Token Account | Solana](#close-token-account-solana) - [Transfer Tokens | Solana](#transfer-tokens-solana) - [Create a Token Account | Solana](#create-a-token-account-solana) - [Revoke Delegate | Solana](#revoke-delegate-solana) - [Thaw Account | Solana](#thaw-account-solana) - [Burn Tokens | Solana](#burn-tokens-solana) - [Approve Delegate | Solana](#approve-delegate-solana) --- # Learn how the Solana blockchain works | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept Solana Documentation ==================== Solana is the high-performance blockchain designed for mass adoption. Learn why Solana is the top choice for developers looking to build scalable blockchain applications. Search or ask AI⌘K Copy MarkdownOpen [Getting Started](https://solana.com/docs#getting-started) ----------------------------------------------------------- [### Quickstart\ \ Build your first Solana program directly in the browser](https://solana.com/docs/intro/quick-start) [### Setup Local Environment\ \ Install dependencies for Solana development](https://solana.com/docs/intro/installation) ### [Build Faster with Solana Developer Templates](https://solana.com/docs#build-faster-with-solana-developer-templates) [### Explore Developer Templates\ \ Build faster with production-ready templates for dApps, DeFi protocols, NFT marketplaces, and more. Get started with battle-tested code patterns optimized for the Solana ecosystem.](https://solana.com/developers/templates) [Try Solana: Play 2048](https://solana.com/docs#try-solana-play-2048) ---------------------------------------------------------------------- Play 2048 on Solana where every move sends a transaction. Click "Play" to start with a funded devnet wallet and use the arrow keys to play. If on mobile, swipe to control the tiles. ### Play Solana 2048 Built by [Jonas](https://x.com/SolPlay_jonas) , from the Solana Foundation DevRel team. [Start Learning](https://solana.com/docs#start-learning) --------------------------------------------------------- Learn the key concepts specific to Solana development. [### Accounts\ \ How Solana stores data](https://solana.com/docs/core/accounts) [### Fees on Solana\ \ Costs to send transactions on Solana](https://solana.com/docs/core/fees) [### Transactions\ \ How to interact with the Solana network](https://solana.com/docs/core/transactions) [### Programs\ \ Smart contracts on Solana](https://solana.com/docs/core/programs) [### Programs Derived Address\ \ How to generate deterministic addresses](https://solana.com/docs/core/pda) [### Cross Program Invocation\ \ How to call one program from another](https://solana.com/docs/core/cpi) ### [Client Side Development](https://solana.com/docs#client-side-development) The following SDKs are the official SDKs for Solana built by [Anza](https://anza.xyz/) . #### [Official SDKs](https://solana.com/docs#official-sdks) | Language | SDK | | --- | --- | | Rust | [solana\_sdk](https://solana.com/docs/clients/official/rust) | | Typescript (Client) | [@solana/client](https://solana.com/docs/clients/official/javascript#solana-client) | | Typescript (React) | [@solana/react-hooks](https://solana.com/docs/clients/official/javascript#solana-react-hooks) | | Typescript (Recommended) | [@solana/kit](https://solana.com/docs/clients/official/javascript#solana-kit) | | Typescript (Legacy) | [@solana/web3.js](https://solana.com/docs/clients/official/javascript#solana-web3js) | #### [Community SDKs](https://solana.com/docs#community-sdks) The following are community-contributed SDKs for various languages: | Language | SDK | | --- | --- | | Python | [solders](https://github.com/kevinheavey/solders) | | Java | [sava](https://sava.software/) or [solanaj](https://github.com/skynetcap/solanaj) or [solana4j](https://github.com/LMAX-Exchange/solana4j) | | C++ | [solcpp](https://github.com/mschneider/solcpp) or [solana-c](https://github.com/VAR-META-Tech/solana-c-sdk) | | Go | [solana-go](https://github.com/gagliardetto/solana-go) | | Kotlin | [sol4k](https://github.com/sol4k/sol4k) or [solanaKT](https://github.com/metaplex-foundation/SolanaKT) | | Dart | [solana](https://github.com/espresso-cash/espresso-cash-public/tree/master/packages/solana) | | C# | [solnet](https://github.com/bmresearch/Solnet) | | GdScript | [godot](https://github.com/Virus-Axel/godot-solana-sdk/) | Community SDKs are not guaranteed to be up to date or include all features of the official SDKs. [Running a validator](https://solana.com/docs#running-a-validator) ------------------------------------------------------------------- Explore what it takes to operate a Solana validator and help secure the network. [### Validators\ \ Individual nodes securing the Solana network](https://docs.anza.xyz/validator/anatomy) [### System Requirements\ \ Recommended hardware requirements and SOL required to operate a validator](https://docs.anza.xyz/operations/requirements) [### Validator Setup\ \ Setup a validator and get connected to a cluster for the first time](https://docs.anza.xyz/operations/setup-a-validator) [Getting Support](https://solana.com/docs#getting-support) ----------------------------------------------------------- Get help from the Solana community on [Solana StackExchange](https://solana.stackexchange.com/) . Is this page helpful? [Next\ \ Quick Installation](https://solana.com/docs/intro/installation) ### Table of Contents [Getting Started](https://solana.com/docs#getting-started) [Build Faster with Solana Developer Templates](https://solana.com/docs#build-faster-with-solana-developer-templates) [Try Solana: Play 2048](https://solana.com/docs#try-solana-play-2048) [Start Learning](https://solana.com/docs#start-learning) [Client Side Development](https://solana.com/docs#client-side-development) [Official SDKs](https://solana.com/docs#official-sdks) [Community SDKs](https://solana.com/docs#community-sdks) [Running a validator](https://solana.com/docs#running-a-validator) [Getting Support](https://solana.com/docs#getting-support) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Learn how the Solana blockchain works | Solana --- # Core Concepts | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) ============================================== Copy MarkdownOpen To build on Solana, it's essential to understand key concepts unique to Solana development. This section covers the core concepts you need to understand as you start building on Solana, including accounts, transactions, programs, and more. [Accounts](https://solana.com/docs/core#accounts) -------------------------------------------------- All data on the Solana blockchain is stored as an Account. The structure of the Solana blockchain resembles a key-value store, in which the key is the on-chain address and the value is an Account. Learn more about [Accounts](https://solana.com/docs/core/accounts) . [Transactions and Instructions](https://solana.com/docs/core#transactions-and-instructions) -------------------------------------------------------------------------------------------- To interact with the Solana network, a user must send a transaction. A transaction is a set of one or more instructions—an instruction is a specific operation to be processed. The execution logic for an instruction is stored on a program deployed to the Solana network. Learn more about [Transactions](https://solana.com/docs/core/transactions) and [Instructions](https://solana.com/docs/core/transactions#instruction) . [Fees](https://solana.com/docs/core#fees) ------------------------------------------ There are three different types of fees that can be incurred when using the Solana blockchain: * **Transaction Fees**: A fee to have validators process transactions & instructions * **Prioritization Fees**: An optional fee to boost a transaction's processing order * **Rent**: A withheld balance to keep data stored on-chain Learn more about [Fees on Solana](https://solana.com/docs/core/fees) . [Programs on Solana](https://solana.com/docs/core#programs-on-solana) ---------------------------------------------------------------------- On Solana, smart contracts are called Programs. Each program is stored in an on-chain account and contains executable code with specific instructions. These instructions represent the program's functionality and are invoked by sending a transaction to the network. Learn more about [Programs on Solana](https://solana.com/docs/core/programs) . [Program Derived Address](https://solana.com/docs/core#program-derived-address) -------------------------------------------------------------------------------- Program-derived addresses (PDAs) allow developers to create hashmap-like structures on-chain using a predefined set of inputs (e.g. strings, numbers, and other account addresses). PDAs allow for two important use cases: * **Deterministic Account Addresses**: Predefined inputs (seeds) and a program ID are combined to deterministically derive an address. * **Program Signing**: A Solana programs can sign for PDAs, which are derived from its program ID. Learn more about [Program Derived Address](https://solana.com/docs/core/pda) . [Cross-program Invocation](https://solana.com/docs/core#cross-program-invocation) ---------------------------------------------------------------------------------- Cross-program invocation (CPI) occurs when one program invokes an instruction from another. This allows for the composability of Solana programs. To conceptualize the concept, imagine a program's set of instructions as a set of API endpoints. A CPI occurs when one endpoint invokes another. Learn more about [Cross Program Invocation](https://solana.com/docs/core/cpi) . [Tokens](https://solana.com/docs/core#tokens) ---------------------------------------------- Tokens are digital assets that represent ownership over diverse categories of assets. Tokenization enables the digitalization of property rights—a fundamental component for managing fungible and non-fungible assets. * **Fungible Tokens**: Interchangeable and divisible assets of the same type and value (ex. USDC). * **Non-fungible Tokens (NFT):** Ownership of indivisible assets (e.g. artwork). Learn more about [Tokens on Solana](https://solana.com/docs/core/tokens) . [Clusters and Endpoints](https://solana.com/docs/core#clusters-and-endpoints) ------------------------------------------------------------------------------ The Solana blockchain has several different groups of validators, known as [Clusters](https://solana.com/docs/references/clusters) . Each cluster serves a different purpose and contains dedicated nodes to fulfill [JSON-RPC](https://solana.com/docs/rpc/) requests. There are three primary clusters on the Solana network, shown in the table below. | Name | Endpoint | Use | | --- | --- | --- | | Mainnet | `https://api.mainnet.solana.com` | Production | | Devnet | `https://api.devnet.solana.com` | Developer experimentation | | Testnet | `https://api.testnet.solana.com` | Validator testing | Learn more about [Clusters and Endpoints](https://solana.com/docs/references/clusters) . Is this page helpful? [Previous\ \ Composing Multiple Programs](https://solana.com/docs/intro/quick-start/cross-program-invocation) [Next\ \ Accounts](https://solana.com/docs/core/accounts) ### Table of Contents [Accounts](https://solana.com/docs/core#accounts) [Transactions and Instructions](https://solana.com/docs/core#transactions-and-instructions) [Fees](https://solana.com/docs/core#fees) [Programs on Solana](https://solana.com/docs/core#programs-on-solana) [Program Derived Address](https://solana.com/docs/core#program-derived-address) [Cross-program Invocation](https://solana.com/docs/core#cross-program-invocation) [Tokens](https://solana.com/docs/core#tokens) [Clusters and Endpoints](https://solana.com/docs/core#clusters-and-endpoints) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Core Concepts | Solana --- # Transaction Fees | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Transaction Fees](https://solana.com/docs/core/fees) ====================================================== Copy MarkdownOpen Every Solana transaction requires a transaction fee, paid in SOL. Transaction fees are split into two parts: the base fee and the prioritization fee. The base fee compensates validators for processing the transaction. The prioritization fee is an optional fee, to increase the chance that the current leader will process your transaction. [Base fee](https://solana.com/docs/core/fees#base-fee) ------------------------------------------------------- Every transaction costs 5000 [lamports](https://solana.com/docs/references/terminology#lamport) per included signature. This fee is paid by the first signer on the transaction. Only accounts owned by the System Program can pay transaction fees. The base fee is split as follows: * **50% burned:** Half is [burned](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/fee-calculator/src/lib.rs#L70) (taken out of the circulating SOL supply). * **50% distributed:** Half is [paid to the validator](https://github.com/anza-xyz/agave/blob/e621336acad4f5d6e5b860eaa1b074b01c99253c/runtime/src/bank/fee_distribution.rs#L58-L62) that processed the transaction. [Prioritization fee](https://solana.com/docs/core/fees#prioritization-fee) --------------------------------------------------------------------------- A [prioritization fee](https://github.com/anza-xyz/agave/blob/v2.2.14/compute-budget/src/compute_budget_limits.rs#L47-L48) is an optional fee used to increase the chance that the current leader (validator) will process your transaction. The validator receives [100% of the priority fee](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0096-reward-collected-priority-fee-in-entirety.md) . Prioritization fees can be set by adjusting the transaction's [computation unit](https://solana.com/docs/references/terminology#compute-units) (CU) price and CU limit. (See the [How to Use Priority Fees guide](https://solana.com/developers/guides/advanced/how-to-use-priority-fees) for more details on prioritization fees.) The prioritization fee is calculated as follows: Prioritization fee formula Prioritization fee = CU limit \* CU price The prioritization fee is used to determine your [transaction's priority](https://github.com/anza-xyz/agave/blob/v2.2.14/core/src/banking_stage/transaction_scheduler/receive_and_buffer.rs#L646) , relative to other transactions. It is calculated using the following formula: Transaction priority formula Priority = (Prioritization fee + Base fee) / (1 + CU limit + Signature CUs + Write lock CUs) #### [Compute unit limit](https://solana.com/docs/core/fees#compute-unit-limit) By [default](https://github.com/anza-xyz/agave/blob/v2.1.13/compute-budget/src/compute_budget.rs#L149-L197) , each instruction is allocated [200,000 CUs](https://github.com/anza-xyz/agave/blob/v2.1.13/compute-budget/src/compute_budget_limits.rs#L10) and each transaction is allocated [1.4 million CUs](https://github.com/anza-xyz/agave/blob/v2.1.13/compute-budget/src/compute_budget_limits.rs#L14) . You can change these defaults by including a [`SetComputeUnitLimit`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/src/compute_budget.rs#L42-L44) instruction in your transaction. To calculate the appropriate CU limit for your transaction, we recommend the following steps: 1. Estimate the required CU units by [simulating](https://solana.com/developers/guides/advanced/how-to-request-optimal-compute) the transaction 2. Add a 10% safety margin to this estimate The priority fee is determined by the requested compute unit limit transaction, _not_ the actual number of compute units used. If you set a compute unit limit that's too high or use the default amount, you may pay for unused compute units. #### [Compute unit price](https://solana.com/docs/core/fees#compute-unit-price) The compute unit price is an optional amount of [micro-lamports](https://solana.com/docs/references/terminology#micro-lamports) paid for each requested CU. You can think of the CU price as a tip to encourage the validator to prioritize your transaction. To set the CU price, include a [`SetComputeUnitPrice`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/src/compute_budget.rs#L48-L50) instruction in your transaction. The default CU price is 0, meaning the default prioritization fee is also 0. For help determining the best CU price for your transaction, see the real-time CU price recommendation provided listed in the table below. | Provider | Priority Fee API | | --- | --- | | [Helius](https://www.helius.dev/) | [Documentation](https://docs.helius.dev/solana-apis/priority-fee-api) | | [QuickNode](https://www.quicknode.com/) | [Documentation](https://marketplace.quicknode.com/add-on/solana-priority-fee) | | [Triton](https://triton.one/) | [Documentation](https://docs.triton.one/chains/solana/improved-priority-fees-api) | #### [Example](https://solana.com/docs/core/fees#example) The examples below show how to set the CU limit and CU price on a transaction using Solana SDKs. | SDK | Source Code Reference | | --- | --- | | `@solana/web3.js` (Typescript) | [`ComputeBudgetProgram`](https://github.com/solana-foundation/solana-web3.js/blob/v1.98.0/src/programs/compute-budget.ts#L218) | | `solana-sdk` (Rust) | [`ComputeBudgetInstruction`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/src/compute_budget.rs#L17-L31) | Typescript Rust const limitInstruction \= ComputeBudgetProgram.setComputeUnitLimit({ units: 300\_000 }); const priceInstruction \= ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 }); Typescript Rust import { LAMPORTS\_PER\_SOL, SystemProgram, Transaction, Keypair, Connection, ComputeBudgetProgram, sendAndConfirmTransaction } from "@solana/web3.js"; const connection \= new Connection("http://localhost:8899", "confirmed"); const sender \= Keypair.generate(); const recipient \= new Keypair(); const airdropSignature \= await connection.requestAirdrop( sender.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(airdropSignature, "confirmed"); // Create compute budget instructions const limitInstruction \= ComputeBudgetProgram.setComputeUnitLimit({ units: 300\_000 }); const priceInstruction \= ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 }); const transferInstruction \= SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: recipient.publicKey, lamports: 0.01 \* LAMPORTS\_PER\_SOL }); // Add the compute budget and transfer instructions to a new transaction const transaction \= new Transaction() .add(limitInstruction) .add(priceInstruction) .add(transferInstruction); const signature \= await sendAndConfirmTransaction(connection, transaction, \[\ \ sender\ \ \]); console.log("Transaction Signature:", signature); Console RunClick to execute the code. Typescript Rust import { LAMPORTS\_PER\_SOL, SystemProgram, Transaction, Keypair, Connection, ComputeBudgetProgram, sendAndConfirmTransaction } from "@solana/web3.js"; const connection \= new Connection("http://localhost:8899", "confirmed"); const sender \= Keypair.generate(); const recipient \= new Keypair(); const airdropSignature \= await connection.requestAirdrop( sender.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(airdropSignature, "confirmed"); // Create compute budget instructions const limitInstruction \= ComputeBudgetProgram.setComputeUnitLimit({ units: 300\_000 }); const priceInstruction \= ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 }); const transferInstruction \= SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: recipient.publicKey, lamports: 0.01 \* LAMPORTS\_PER\_SOL }); // Add the compute budget and transfer instructions to a new transaction const transaction \= new Transaction() .add(limitInstruction) .add(priceInstruction) .add(transferInstruction); const signature \= await sendAndConfirmTransaction(connection, transaction, \[\ \ sender\ \ \]); console.log("Transaction Signature:", signature); Console RunClick to execute the code. Is this page helpful? [Previous\ \ Transactions](https://solana.com/docs/core/transactions) [Next\ \ Programs](https://solana.com/docs/core/programs) ### Table of Contents [Base fee](https://solana.com/docs/core/fees#base-fee) [Prioritization fee](https://solana.com/docs/core/fees#prioritization-fee) [Compute unit limit](https://solana.com/docs/core/fees#compute-unit-limit) [Compute unit price](https://solana.com/docs/core/fees#compute-unit-price) [Example](https://solana.com/docs/core/fees#example) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/fees.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Transaction Fees | Solana --- # Program-Derived Address | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Program-Derived Address](https://solana.com/docs/core/pda) ============================================================ Copy MarkdownOpen A Solana [account address](https://solana.com/docs/core/accounts#account-address) points to the account's location on the blockchain. Many account addresses are the public key of a keypair, in which case the corresponding private key is used to sign transactions involving the account. A useful alternative to a public key address is a program-derived address (PDA). PDAs provide an easy method to store, map, and fetch program state. A PDA is an address that is created deterministically using a program ID and a combination of optional predefined inputs. PDAs look similar to public key addresses, but do not have a corresponding private key. The Solana runtime enables programs to sign for PDAs without needing a private key. Using a PDA eliminates the need to keep track of the account's address. Instead, you can recall the specific inputs used for the PDA's derivation. (To learn how programs use PDAs for signing, see the [Cross Program Invocations](https://solana.com/docs/core/cpi) section.) [Background](https://solana.com/docs/core/pda#background) ---------------------------------------------------------- Solana [keypairs](https://github.com/anza-xyz/solana-sdk/blob/sdk%40v2.2.2/keypair/src/lib.rs#L26) are points on the [Ed25519 curve](https://ed25519.cr.yp.to/) (elliptic-curve cryptography). They consist of a public key and a private key. The public key becomes the account address, and the private key is used to generate valid [signature](https://solana.com/docs/core/transactions#signatures) for the account. Two accounts with on-curve addresses A PDA is intentionally derived to fall off the Ed25519 curve. This means it does not have a valid corresponding private key and can't perform cryptographic operations. (Such as providing a signature.) However, Solana enables programs to sign for PDAs without needing a private key. Off Curve Address You can think of PDAs as a way to create hashmap-like structures on-chain using a predefined set of inputs. (For example, strings, numbers, and other account addresses.) Program Derived Address [Derive a PDA](https://solana.com/docs/core/pda#derive-a-pda) -------------------------------------------------------------- Before creating an account with a PDA, you must first derive the address. Deriving a PDA _does not_ automatically create an on-chain account at that address— the account must be explicitly created through the program used to derive the PDA. You can think of a PDA like an address on a map: just because an address exists doesn't mean there is anything built there. The Solana SDKs support PDA creation with the functions shown in the table below. Each function receives the following input: * **Program ID**: The address of the program being used to derive the PDA. This program can sign on behalf of the PDA. * **Optional seeds**: Predefined inputs, such as strings, numbers or other account addresses. | SDK | Function | | --- | --- | | `@solana/kit` (Typescript) | [`getProgramDerivedAddress`](https://github.com/anza-xyz/kit/blob/v2.1.0/packages/addresses/src/program-derived-address.ts#L157) | | `@solana/web3.js` (Typescript) | [`findProgramAddressSync`](https://github.com/solana-foundation/solana-web3.js/blob/v1.98.0/src/publickey.ts#L212) | | `solana_sdk` (Rust) | [`find_program_address`](https://github.com/anza-xyz/solana-sdk/blob/sdk%40v2.2.2/pubkey/src/lib.rs#L617) | The function uses the program ID and optional seeds, then iterates through bump values to attempt to create a valid program address. The iteration of bump values starts at 255 and decrements by 1 until a valid PDA is found. After a valid PDA is found, the function returns the PDA and the bump seed. The bump seed is an extra byte appended to the optional seeds to ensure a valid off-curve address is generated. PDA Derivation ### [Canonical bump](https://solana.com/docs/core/pda#canonical-bump) A bump seed is an extra byte appended to the optional seeds. The derivation function iterates through bump values, starting at 255 and decrementing by 1, until a value produces a valid off-curve address. The first value that produces a valid off-curve address is called the "canonical bump." The following examples show PDA derivation using all possible bump seeds (255 to 0): Kit example is not included because the [createProgramDerivedAddress](https://github.com/anza-xyz/kit/blob/v2.1.0/packages/addresses/src/program-derived-address.ts#L101) function isn't exported. Legacy Rust import { PublicKey } from "@solana/web3.js"; const programId \= new PublicKey("11111111111111111111111111111111"); const optionalSeed \= "helloWorld"; // Loop through all bump seeds (255 down to 0) for (let bump \= 255; bump \>= 0; bump\--) { try { const PDA \= PublicKey.createProgramAddressSync( \[Buffer.from(optionalSeed), Buffer.from(\[bump\])\], programId ); console.log("bump " + bump + ": " + PDA); } catch (error) { console.log("bump " + bump + ": " + error); } } Console RunClick to execute the code. Legacy Rust import { PublicKey } from "@solana/web3.js"; const programId \= new PublicKey("11111111111111111111111111111111"); const optionalSeed \= "helloWorld"; // Loop through all bump seeds (255 down to 0) for (let bump \= 255; bump \>= 0; bump\--) { try { const PDA \= PublicKey.createProgramAddressSync( \[Buffer.from(optionalSeed), Buffer.from(\[bump\])\], programId ); console.log("bump " + bump + ": " + PDA); } catch (error) { console.log("bump " + bump + ": " + error); } } Console RunClick to execute the code. Expected TS Output Expected Rust Output bump 255: Error: Invalid seeds, address must fall off the curve bump 254: 46GZzzetjCURsdFPb7rcnspbEMnCBXe9kpjrsZAkKb6X bump 253: GBNWBGxKmdcd7JrMnBdZke9Fumj9sir4rpbruwEGmR4y bump 252: THfBMgduMonjaNsCisKa7Qz2cBoG1VCUYHyso7UXYHH bump 251: EuRrNqJAofo7y3Jy6MGvF7eZAYegqYTwH2dnLCwDDGdP bump 250: Error: Invalid seeds, address must fall off the curve ... // remaining bump outputs In this example, the first bump seed throws an error. The first bump seed to derive a valid PDA is 254. Bump seeds 253-251 also derive unique, valid PDAs. This means that given the same optional seeds and `programId`, a bump seed with a different value can still derive a valid PDA. Always include security checks to ensure a PDA passed to the program is derived from the canonical bump. Failure to do so may introduce vulnerabilities that allow unexpected accounts to be used in the program's instructions. It is best practice to only use the canonical bump when deriving PDAs. ### [Examples](https://solana.com/docs/core/pda#examples) The examples below derive a PDA using the Solana SDKs. Click **▷ Run** to execute the code. #### [Derive a PDA with a string seed](https://solana.com/docs/core/pda#derive-a-pda-with-a-string-seed) The example below derives a PDA using a program ID and an optional string seed. Kit Legacy Rust import { Address, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const seeds \= \["helloWorld"\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. Kit Legacy Rust import { Address, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const seeds \= \["helloWorld"\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. #### [Derive a PDA with an address seed](https://solana.com/docs/core/pda#derive-a-pda-with-an-address-seed) The example below derives a PDA using a program ID and an optional address seed. Kit Legacy Rust import { Address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const addressEncoder \= getAddressEncoder(); const optionalSeedAddress \= addressEncoder.encode( "B9Lf9z5BfNPT4d5KMeaBFx8x1G4CULZYR1jA2kmxRDka" as Address ); const seeds \= \[optionalSeedAddress\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. Kit Legacy Rust import { Address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const addressEncoder \= getAddressEncoder(); const optionalSeedAddress \= addressEncoder.encode( "B9Lf9z5BfNPT4d5KMeaBFx8x1G4CULZYR1jA2kmxRDka" as Address ); const seeds \= \[optionalSeedAddress\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. #### [Derive a PDA with multiple seeds](https://solana.com/docs/core/pda#derive-a-pda-with-multiple-seeds) The example below derives a PDA using a program ID and multiple optional seeds. Kit Legacy Rust import { Address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const optionalSeedString \= "helloWorld"; const addressEncoder \= getAddressEncoder(); const optionalSeedAddress \= addressEncoder.encode( "B9Lf9z5BfNPT4d5KMeaBFx8x1G4CULZYR1jA2kmxRDka" as Address ); const seeds \= \[optionalSeedString, optionalSeedAddress\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. Kit Legacy Rust import { Address, getAddressEncoder, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const optionalSeedString \= "helloWorld"; const addressEncoder \= getAddressEncoder(); const optionalSeedAddress \= addressEncoder.encode( "B9Lf9z5BfNPT4d5KMeaBFx8x1G4CULZYR1jA2kmxRDka" as Address ); const seeds \= \[optionalSeedString, optionalSeedAddress\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. [Create a PDA account](https://solana.com/docs/core/pda#create-a-pda-account) ------------------------------------------------------------------------------ The example below uses the [Anchor framework](https://www.anchor-lang.com/docs) to create a new account with a program-derived address. The program includes a single `initialize` instruction to create the new account, which will store the user address and bump seed used to derive the PDA. Program use anchor\_lang::prelude::\*; declare\_id!("75GJVCJNhaukaa2vCCqhreY31gaphv7XTScBChmr1ueR"); #\[program\] pub mod pda\_account { use super::\*; pub fn initialize(ctx: Context) \-> Result<()> { let account\_data \= &mut ctx.accounts.pda\_account; // store the address of the \`user\` account\_data.user \= \*ctx.accounts.user.key; // store the canonical bumpd account\_data.bump \= ctx.bumps.pda\_account; Ok(()) } } #\[derive(Accounts)\] pub struct Initialize<'info\> { #\[account(mut)\] pub user: Signer<'info\>, #\[account(\ \ init,\ \ // define the seeds to derive the PDA\ \ seeds \= \[b"data", user.key().as\_ref()\],\ \ // use the canonical bump\ \ bump,\ \ payer \= user,\ \ space \= 8 + DataAccount::INIT\_SPACE\ \ )\] pub pda\_account: Account<'info, DataAccount\>, pub system\_program: Program<'info, System\>, } #\[account\] #\[derive(InitSpace)\] pub struct DataAccount { pub user: Pubkey, pub bump: u8, } The `init` constraint tells Anchor to [invoke the System Program](https://solana.com/docs/core/programs#the-system-program) to create a new account using the PDA as the address. The seeds used to create the PDA are: * The address of the user account provided in the instruction * The fixed string: "data" * The canonical bump seed In this example, the bump constraint is not assigned a value, so Anchor will use `find_program_address` to derive the PDA and find the bump. pda\_account #\[account(\ \ init,\ \ seeds \= \[b"data", user.key().as\_ref()\],\ \ bump,\ \ payer \= user,\ \ space \= 8 + DataAccount::INIT\_SPACE\ \ )\] pub pda\_account: Account<'info, DataAccount\>, The test file below contains a transaction that invokes the `initialize` instruction to create a new account with a program-derived address. The file contains code to derive the PDA. The example also shows how to fetch the new account that will be created. Test import \* as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; import { PdaAccount } from "../target/types/pda\_account"; import { PublicKey } from "@solana/web3.js"; describe("pda-account", () \=> { const provider \= anchor.AnchorProvider.env(); anchor.setProvider(provider); const program \= anchor.workspace.PdaAccount as Program; const user \= provider.wallet as anchor.Wallet; // Derive the PDA address using the seeds specified on the program const \[PDA\] \= PublicKey.findProgramAddressSync( \[Buffer.from("data"), user.publicKey.toBuffer()\], program.programId ); it("Is initialized!", async () \=> { const transactionSignature \= await program.methods .initialize() .accounts({ user: user.publicKey }) .rpc(); console.log("Transaction Signature:", transactionSignature); }); it("Fetch Account", async () \=> { const pdaAccount \= await program.account.dataAccount.fetch(PDA); console.log(JSON.stringify(pdaAccount, null, 2)); }); }); If you invoke the `initialize` instruction again with the same `user` address seed, the transaction will fail. This happens because an account already exists at the derived address. Is this page helpful? [Previous\ \ Programs](https://solana.com/docs/core/programs) [Next\ \ Cross Program Invocation](https://solana.com/docs/core/cpi) ### Table of Contents [Background](https://solana.com/docs/core/pda#background) [Derive a PDA](https://solana.com/docs/core/pda#derive-a-pda) [Canonical bump](https://solana.com/docs/core/pda#canonical-bump) [Examples](https://solana.com/docs/core/pda#examples) [Derive a PDA with a string seed](https://solana.com/docs/core/pda#derive-a-pda-with-a-string-seed) [Derive a PDA with an address seed](https://solana.com/docs/core/pda#derive-a-pda-with-an-address-seed) [Derive a PDA with multiple seeds](https://solana.com/docs/core/pda#derive-a-pda-with-multiple-seeds) [Create a PDA account](https://solana.com/docs/core/pda#create-a-pda-account) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/pda.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Program-Derived Address | Solana --- # Tokens on Solana | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) =================================================== Copy MarkdownOpen Tokens are digital assets that represent ownership over diverse categories of assets. Tokenization enables the digitalization of property rights. Tokens on Solana are referred to as SPL ([Solana Program Library](https://github.com/solana-program) ) Tokens. This section covers the basic concepts of how tokens are represented on Solana. Refer to the [SPL Token Basics](https://solana.com/docs/tokens/basics) section for code examples. [Key Points](https://solana.com/docs/tokens#key-points) -------------------------------------------------------- * [Token Programs](https://solana.com/docs/tokens#token-program) contain all instruction logic for interacting with tokens on the network (both fungible and non-fungible). * A [Mint Account](https://solana.com/docs/tokens#mint-account) represents a specific token and stores global metadata about the token such as the total supply and mint authority (address authorized to create new units of a token). * A [Token Account](https://solana.com/docs/tokens#token-account) tracks individual ownership of tokens for a specific mint account for a specific owner. * An [Associated Token Account](https://solana.com/docs/tokens#associated-token-account) is a Token Account created with an address derived from the owner and mint account addresses. [Token Programs](https://solana.com/docs/tokens#token-programs) ---------------------------------------------------------------- The Solana ecosystem has two main Token Programs. Source code for both programs below. [### Token Program (Original)\ \ * Basic token capability (mint, transfer, etc.)\ * Immutable and widely used](https://github.com/solana-program/token) [### Token Extension Program (Token 2022)\ \ * Includes all original Token Program features\ * Adds features through "extensions"](https://github.com/solana-program/token-2022) Token Programs contains all instruction logic for interacting with tokens on the network (both fungible and non-fungible). All tokens on Solana are effectively [data accounts](https://solana.com/docs/core/accounts#data-account) owned by a Token Program. Token Program ### [Mint Account](https://solana.com/docs/tokens#mint-account) Tokens on Solana are uniquely identified by the address of a [Mint Account](https://github.com/solana-program/token/blob/6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a/program/src/state.rs#L16-L30) owned by the Token Program. This account acts as a global counter for a specific token and stores data such as: * **Supply**: Total supply of the token * **Decimals**: Decimal precision of the token * **Mint authority**: The account authorized to create new units of the token, increasing the supply * **Freeze authority**: The account authorized to freeze tokens in a Token Account, preventing them from being transferred or burned Mint Account The full details stored on each Mint Account include the following: Mint Account State pub struct Mint { /// Optional authority used to mint new tokens. The mint authority may only /// be provided during mint creation. If no mint authority is present /// then the mint has a fixed supply and no further tokens may be /// minted. pub mint\_authority: COption, /// Total supply of tokens. pub supply: u64, /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, /// Is \`true\` if this structure has been initialized pub is\_initialized: bool, /// Optional authority to freeze token accounts. pub freeze\_authority: COption, } For reference, here is a Solana Explorer link to the [USDC Mint Account](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) . ### [Token Account](https://solana.com/docs/tokens#token-account) The Token Program creates [Token Accounts](https://github.com/solana-program/token/blob/6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a/program/src/state.rs#L87-L108) to track individual ownership of each token unit. A Token Account stores data such as: * **Mint**: The token the Token Account holds units of * **Owner**: The account authorized to transfer tokens from the Token Account * **Amount**: Number of the tokens the Token Account currently holds Token Account The full details stored on each Token Account include the following: Token Account State pub struct Account { /// The mint associated with this account pub mint: Pubkey, /// The owner of this account. pub owner: Pubkey, /// The amount of tokens this account holds. pub amount: u64, /// If \`delegate\` is \`Some\` then \`delegated\_amount\` represents /// the amount authorized by the delegate pub delegate: COption, /// The account's state pub state: AccountState, /// If is\_native.is\_some, this is a native token, and the value logs the /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. pub is\_native: COption, /// The amount delegated pub delegated\_amount: u64, /// Optional authority to close the account. pub close\_authority: COption, } A wallet needs a token account for each token (mint) it wants to hold, with the wallet address set as the token account owner. Each wallet can own multiple token accounts for the same token (mint), but a token account can only have one owner and hold units of one token (mint). Account Relationship Note that each Token Account's data includes an `owner` field identifying who has authority over the Token Account. This differs from the program owner specified in the base [Account](https://solana.com/docs/core/accounts#account-type) type, which is the Token Program for all Token Accounts. ### [Associated Token Account](https://solana.com/docs/tokens#associated-token-account) Associated Token Accounts simplify the process of finding a token account's address for a specific mint and owner. Think of the Associated Token Account as the "default" token account for a specific mint and owner. An Associated Token Account is created with an address derived from the owner's address and the mint account's address. It's important to understand that an Associated Token Account is just a token account with a specific address. This introduces a key concept in Solana development: [Program Derived Address (PDA)](https://solana.com/docs/core/pda) . A PDA derives an address deterministically using predefined inputs, making it easy to find the address of an account. Associated Token Account Note that each wallet needs its own token account to hold tokens from the same mint. Accounts Relationship Expanded [Token CLI Examples](https://solana.com/docs/tokens#token-cli-examples) ------------------------------------------------------------------------ The `spl-token` CLI helps you experiment with SPL tokens. The examples below use the [Solana Playground](https://beta.solpg.io/) terminal to run CLI commands directly in the browser without local installation. Creating tokens and accounts requires SOL for account rent deposits and transaction fees. For first-time Solana Playground users, create a Playground wallet and run the `solana airdrop` command in the Playground terminal. You can also get devnet SOL from the public [web faucet](https://faucet.solana.com/) . Terminal $ solana airdrop 2 Copy Run `spl-token --help` to see all available commands. Terminal $ spl-token --help Copy To install the `spl-token` CLI locally, run: Terminal $ cargo install spl-token-cli Copy Find more examples in the `spl-token` [documentation](https://www.solana-program.com/docs/token) . The account addresses shown in your terminal output differ from the examples below. Use the addresses from your Playground terminal when following along. For example, the `create-token` command outputs a mint account address with your Playground wallet as the mint authority. ### [Create a New Token](https://solana.com/docs/tokens#create-a-new-token) To create a new token (mint account), run: Terminal $ spl-token create-token Copy The output looks like: Terminal Output Creating token 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Address: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Decimals: 9 Signature: 44fvKfT1ezBUwdzrCys3fvCdFxbLMnNvBstds76QZyE6cXag5NupBprSXwxPTzzjrC3cA6nvUZaLFTvmcKyzxrm1 A new mint account starts with zero supply. Check the current supply with: Terminal $ spl-token supply Copy The `supply` command for a new token returns `0`: Example spl-token supply 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Creating a new Mint Account requires a transaction with two instructions. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ce32ecffcf4b13384d00f) . 1. The System Program creates a new account with space for the Mint Account data and transfers ownership to the Token Program. 2. The Token Program initializes the data of the new account as a Mint Account ### [Create Token Account](https://solana.com/docs/tokens#create-token-account) To hold tokens of a specific mint, create a token account: Terminal $ spl-token create-account Copy Example command: Example spl-token create-account 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Output: Terminal Output Creating account AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 Signature: 2BtrynuCLX9CNofFiaw6Yzbx6hit66pup9Sk7aFjwU2NEbFz7NCHD9w9sWhrCfEd73XveAGK1DxFpJoQZPXU9tS1 The `create-account` command creates an associated token account with your wallet address as the owner. To create a token account with a different owner: Terminal $ spl-token create-account --owner Copy Note: `` specifies the mint account for the token account. Example command: Example spl-token create-account \--owner 2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Output: Terminal Output Creating account Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Signature: 44vqKdfzspT592REDPY4goaRJH3uJ3Ce13G4BCuUHg35dVUbHuGTHvqn4ZjYF9BGe9QrjMfe9GmuLkQhSZCBQuEt Creating an Associated Token Account requires one instruction that invokes the [Associated Token Program](https://github.com/solana-program/associated-token-account) . Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ce868cffcf4b13384d011) . The Associated Token Program uses [Cross Program Invocations](https://solana.com/docs/core/cpi) to: * [Invoke the System Program](https://github.com/solana-program/associated-token-account/blob/9d94201e8158f06015ff80ad47fefac62a2ec450/program/src/tools/account.rs#L19) to create a new account using the provided PDA as the address * [Invoke the Token Program](https://github.com/solana-program/associated-token-account/blob/9d94201e8158f06015ff80ad47fefac62a2ec450/program/src/processor.rs#L138-L161) to initialize the Token Account data To create a new Token Account with a new keypair instead of an Associated Token Account address, send a transaction with two instructions. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ce716cffcf4b13384d010) . 1. The System Program creates a new account with space for the Token Account data and transfers ownership to the Token Program. 2. The Token Program initializes the data as a Token Account ### [Mint Tokens](https://solana.com/docs/tokens#mint-tokens) To create new units of a token, mint tokens to a Token Account: Terminal $ spl-token mint \[OPTIONS\] \[--\] \[RECIPIENT\_TOKEN\_ACCOUNT\_ADDRESS\] Copy Example command: Example spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 Output: Terminal Output Minting 100 tokens Token: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Recipient: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 Signature: 2NJ1m7qCraPSBAVxbr2ssmWZmBU9Jc8pDtJAnyZsZJRcaYCYMqq1oRY1gqA4ddQno3g3xcnny5fzr1dvsnFKMEqG To mint tokens to a different token account: Example spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 -- Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Output: Terminal Output Minting 100 tokens Token: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Signature: 3SQvNM3o9DsTiLwcEkSPT1Edr14RgE2wC54TEjonEP2swyVCp2jPWYWdD6RwXUGpvDNUkKWzVBZVFShn5yntxVd7 The `MintTo` instruction on the Token Program creates new tokens. The mint authority must sign the transaction. The instruction mints tokens to a Token Account and increases the total supply on the Mint Account. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660cea45cffcf4b13384d012) . ### [Transfer Tokens](https://solana.com/docs/tokens#transfer-tokens) To transfer tokens between token accounts: Terminal spl-token transfer \[OPTIONS\] Example command: Example spl-token transfer 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Output: Terminal Output Transfer 100 tokens Sender: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Signature: 5y6HVwV8V2hHGLTVmTmdySRiEUCZnWmkasAvJ7J6m7JR46obbGKCBqUFgLpZu5zQGwM4Xy6GZ4M5LKd1h6Padx3o The `Transfer` instruction on the Token Program handles token transfers. The owner of the sender's Token Account must sign the transaction. The instruction moves tokens between Token Accounts. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ced84cffcf4b13384d013) . Both sender and recipient need token accounts for the specific token (mint). The sender can include instructions to create the recipient's token account in the same transaction. ### [Create Token Metadata](https://solana.com/docs/tokens#create-token-metadata) The Token Extensions Program lets you store metadata (name, symbol, image link) directly on the Mint Account. To create a token with metadata extension: Example spl-token create-token \--program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \--enable-metadata Output: Terminal Output Creating token BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb To initialize metadata inside the mint, please run \`spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP \`, and sign with the mint authority. Address: BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP Decimals: 9 Signature: 5iQofFeXdYhMi9uTzZghcq8stAaa6CY6saUwcdnELST13eNSifiuLbvR5DnRt311frkCTUh5oecj8YEvZSB3wfai To initialize the metadata: Terminal spl-token initialize-metadata The token URI links to off-chain metadata. See an example JSON format [here](https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json) . Example command: Example spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP "TokenName" "TokenSymbol" "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json" View the metadata on [Solana Explorer](https://explorer.solana.com/address/BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP?cluster=devnet) . Learn more in the [Metadata Extension Guide](https://solana.com/developers/guides/token-extensions/metadata-pointer) . For details about Token Extensions, see the Token Extensions [Getting Started Guide](https://solana.com/developers/guides/token-extensions/getting-started) and the [SPL documentation](https://www.solana-program.com/docs/token-2022/extensions) . Is this page helpful? [Previous\ \ Cross Program Invocation](https://solana.com/docs/core/cpi) [Next\ \ SPL Token Basics](https://solana.com/docs/tokens/basics) ### Table of Contents [Key Points](https://solana.com/docs/tokens#key-points) [Token Programs](https://solana.com/docs/tokens#token-programs) [Mint Account](https://solana.com/docs/tokens#mint-account) [Token Account](https://solana.com/docs/tokens#token-account) [Associated Token Account](https://solana.com/docs/tokens#associated-token-account) [Token CLI Examples](https://solana.com/docs/tokens#token-cli-examples) [Create a New Token](https://solana.com/docs/tokens#create-a-new-token) [Create Token Account](https://solana.com/docs/tokens#create-token-account) [Mint Tokens](https://solana.com/docs/tokens#mint-tokens) [Transfer Tokens](https://solana.com/docs/tokens#transfer-tokens) [Create Token Metadata](https://solana.com/docs/tokens#create-token-metadata) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Tokens on Solana | Solana --- # Cross Program Invocation | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Cross Program Invocation](https://solana.com/docs/core/cpi) ============================================================= Copy MarkdownOpen A cross-program invocation (CPI) occurs when one Solana program directly invokes the instructions of another program. This allows for program composability. If you think of a Solana [instruction](https://solana.com/docs/core/instructions) as an API endpoint that a program exposes to the network, a CPI is like one endpoint internally invoking another. When making a CPI, a program can [sign](https://solana.com/docs/references/terminology#signature) on behalf of a [PDA](https://solana.com/docs/core/pda) derived from its program ID. These signer privileges extend from the caller program to the callee program. Cross-program invocation example When making a CPI, account privileges extend from one program to another. Let's say Program A receives an instruction with a signer account and a writable account. Program A then makes a CPI to Program B. Now, Program B can use the same accounts as Program A, with their original permissions. (Meaning Program B can sign with the signer account and can write to the writable account.) If Program B makes its own CPIs, it can pass these same permissions forward, up to a depth of 4. The maximum height of the program instruction invocation is called the [`max_instruction_stack_depth`](https://github.com/anza-xyz/agave/blob/v2.1.13/compute-budget/src/compute_budget.rs#L38) and is set to the [MAX\_INSTRUCTION\_STACK\_DEPTH](https://github.com/anza-xyz/agave/blob/v2.1.13/compute-budget/src/compute_budget.rs#L13) constant of 5. The stack height begins at 1 for the initial transaction and increases by 1 each time a program invokes another instruction, limiting invocation depth for CPIs to 4. [CPIs with PDA signers](https://solana.com/docs/core/cpi#cpis-with-pda-signers) -------------------------------------------------------------------------------- When a CPI requires a PDA signer, the [`invoke_signed`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/program.rs#L51-L73) function is used. It takes the signer seeds used for deriving signer [PDAs](https://solana.com/docs/core/pda) . The Solana runtime internally calls [`create_program_address`](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/bpf_loader/src/syscalls/cpi.rs#L552) using the `signers_seeds` and the `program_id` of the caller program. When a PDA is verified, it is [added as a valid signer](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/bpf_loader/src/syscalls/cpi.rs#L554) . Invoke signed pub fn invoke\_signed( instruction: &Instruction, account\_infos: &\[AccountInfo\], signers\_seeds: &\[&\[&\[u8\]\]\], ) \-> ProgramResult { // --snip-- invoke\_signed\_unchecked(instruction, account\_infos, signers\_seeds) } The examples below make a CPI with PDA signers using Anchor and Native Rust. Each example includes a single instruction to transfer SOL from a PDA to a recipient account, using a CPI signed by the PDA. #### [Anchor](https://solana.com/docs/core/cpi#anchor) The following examples show three approaches to implementing CPIs in an [Anchor](https://www.anchor-lang.com/docs) program. The examples are functionally equivalent, but each demonstrates a different level of abstraction. * **Example 1**: Uses Anchor's `CpiContext` and helper function. * **Example 2**: Uses the `system_instruction::transfer` function from `solana_program` crate. (Example 1 is an abstraction of this implementation.) * **Example 3**: Constructs the CPI instruction manually. This approach is useful when there is no crate available to help build the instruction you want to invoke. Example 1 Example 2 Example 3 Test use anchor\_lang::prelude::\*; use anchor\_lang::system\_program::{transfer, Transfer}; declare\_id!("BrcdB9sV7z9DvF9rDHG263HUxXgJM3iCQdF36TcxbFEn"); #\[program\] pub mod cpi { use super::\*; pub fn sol\_transfer(ctx: Context, amount: u64) \-> Result<()> { let from\_pubkey \= ctx.accounts.pda\_account.to\_account\_info(); let to\_pubkey \= ctx.accounts.recipient.to\_account\_info(); let program\_id \= ctx.accounts.system\_program.to\_account\_info(); let seed \= to\_pubkey.key(); let bump\_seed \= ctx.bumps.pda\_account; let signer\_seeds: &\[&\[&\[u8\]\]\] \= &\[&\[b"pda", seed.as\_ref(), &\[bump\_seed\]\]\]; let cpi\_context \= CpiContext::new( program\_id, Transfer { from: from\_pubkey, to: to\_pubkey, }, ) .with\_signer(signer\_seeds); transfer(cpi\_context, amount)?; Ok(()) } } #\[derive(Accounts)\] pub struct SolTransfer<'info\> { #\[account(\ \ mut,\ \ seeds \= \[b"pda", recipient.key().as\_ref()\],\ \ bump,\ \ )\] pda\_account: SystemAccount<'info\>, #\[account(mut)\] recipient: SystemAccount<'info\>, system\_program: Program<'info, System\>, } #### [Rust](https://solana.com/docs/core/cpi#rust) The example below makes a CPI with PDA signers from a program written in Native Rust. It includes a single instruction that transfers SOL from a PDA account to another. The CPI is signed by the PDA account. (The test file uses [LiteSVM](https://github.com/LiteSVM/litesvm) to test the program.) Example Test use borsh::BorshDeserialize; use solana\_program::{ account\_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program::invoke\_signed, program\_error::ProgramError, pubkey::Pubkey, system\_instruction, }; // Declare program entrypoint entrypoint!(process\_instruction); // Define program instructions #\[derive(BorshDeserialize)\] enum ProgramInstruction { SolTransfer { amount: u64 }, } impl ProgramInstruction { fn unpack(input: &\[u8\]) \-> Result { Self::try\_from\_slice(input).map\_err(|\_| ProgramError::InvalidInstructionData) } } pub fn process\_instruction( program\_id: &Pubkey, accounts: &\[AccountInfo\], instruction\_data: &\[u8\], ) \-> ProgramResult { // Deserialize instruction data let instruction \= ProgramInstruction::unpack(instruction\_data)?; // Process instruction match instruction { ProgramInstruction::SolTransfer { amount } \=> { // Parse accounts let \[pda\_account\_info, recipient\_info, system\_program\_info\] \= accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; // Derive PDA and verify it matches the account provided by client let recipient\_pubkey \= recipient\_info.key; let seeds \= &\[b"pda", recipient\_pubkey.as\_ref()\]; let (expected\_pda, bump\_seed) \= Pubkey::find\_program\_address(seeds, program\_id); if expected\_pda != \*pda\_account\_info.key { return Err(ProgramError::InvalidArgument); } // Create the transfer instruction let transfer\_ix \= system\_instruction::transfer( pda\_account\_info.key, recipient\_info.key, amount, ); // Create signer seeds for PDA let signer\_seeds: &\[&\[&\[u8\]\]\] \= &\[&\[b"pda", recipient\_pubkey.as\_ref(), &\[bump\_seed\]\]\]; // Invoke the transfer instruction with PDA as signer invoke\_signed( &transfer\_ix, &\[\ \ pda\_account\_info.clone(),\ \ recipient\_info.clone(),\ \ system\_program\_info.clone(),\ \ \], signer\_seeds, )?; Ok(()) } } } [CPIs without PDA signers](https://solana.com/docs/core/cpi#cpis-without-pda-signers) -------------------------------------------------------------------------------------- When a CPI doesn't require PDA signers, the [`invoke`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/program.rs#L26-L28) function is used. The `invoke` function calls the `invoke_signed` function with an empty `signers_seeds` array. The empty signers array indicates that no PDAs are required for signing. Invoke function pub fn invoke(instruction: &Instruction, account\_infos: &\[AccountInfo\]) \-> ProgramResult { invoke\_signed(instruction, account\_infos, &\[\]) } The examples below make a CPI using Anchor and Native Rust. It includes a single instruction that transfers SOL from one account to another. #### [Anchor](https://solana.com/docs/core/cpi#anchor-1) The following examples show three approaches to implementing CPIs in an [Anchor](https://www.anchor-lang.com/docs) program. The examples are functionally equivalent, but each demonstrates a different level of abstraction. * **Example 1**: Uses Anchor's `CpiContext` and helper function. * **Example 2**: Uses the `system_instruction::transfer` function from the `solana_program` crate. * **Example 3**: Constructs the CPI instruction manually. This approach is useful when no crate exists to help build the instruction you want to invoke. Example 1 Example 2 Example 3 Test use anchor\_lang::prelude::\*; use anchor\_lang::system\_program::{transfer, Transfer}; declare\_id!("9AvUNHjxscdkiKQ8tUn12QCMXtcnbR9BVGq3ULNzFMRi"); #\[program\] pub mod cpi { use super::\*; pub fn sol\_transfer(ctx: Context, amount: u64) \-> Result<()> { let from\_pubkey \= ctx.accounts.sender.to\_account\_info(); let to\_pubkey \= ctx.accounts.recipient.to\_account\_info(); let program\_id \= ctx.accounts.system\_program.to\_account\_info(); let cpi\_context \= CpiContext::new( program\_id, Transfer { from: from\_pubkey, to: to\_pubkey, }, ); transfer(cpi\_context, amount)?; Ok(()) } } #\[derive(Accounts)\] pub struct SolTransfer<'info\> { #\[account(mut)\] sender: Signer<'info\>, #\[account(mut)\] recipient: SystemAccount<'info\>, system\_program: Program<'info, System\>, } #### [Rust](https://solana.com/docs/core/cpi#rust-1) The following example shows how to make a CPI from a program written in Native Rust. It includes a single instruction that transfers SOL from one account to another. (The test file uses [LiteSVM](https://github.com/LiteSVM/litesvm) to test the program.) Example Test use borsh::BorshDeserialize; use solana\_program::{ account\_info::AccountInfo, entrypoint, entrypoint::ProgramResult, program::invoke, program\_error::ProgramError, pubkey::Pubkey, system\_instruction, }; // Declare program entrypoint entrypoint!(process\_instruction); // Define program instructions #\[derive(BorshDeserialize)\] enum ProgramInstruction { SolTransfer { amount: u64 }, } impl ProgramInstruction { fn unpack(input: &\[u8\]) \-> Result { Self::try\_from\_slice(input).map\_err(|\_| ProgramError::InvalidInstructionData) } } pub fn process\_instruction( \_program\_id: &Pubkey, accounts: &\[AccountInfo\], instruction\_data: &\[u8\], ) \-> ProgramResult { // Deserialize instruction data let instruction \= ProgramInstruction::unpack(instruction\_data)?; // Process instruction match instruction { ProgramInstruction::SolTransfer { amount } \=> { // Parse accounts let \[sender\_info, recipient\_info, system\_program\_info\] \= accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; // Verify the sender is a signer if !sender\_info.is\_signer { return Err(ProgramError::MissingRequiredSignature); } // Create and invoke the transfer instruction let transfer\_ix \= system\_instruction::transfer( sender\_info.key, recipient\_info.key, amount, ); invoke( &transfer\_ix, &\[\ \ sender\_info.clone(),\ \ recipient\_info.clone(),\ \ system\_program\_info.clone(),\ \ \], )?; Ok(()) } } } Is this page helpful? [Previous\ \ Program-Derived Address](https://solana.com/docs/core/pda) [Next\ \ Tokens on Solana](https://solana.com/docs/tokens) ### Table of Contents [CPIs with PDA signers](https://solana.com/docs/core/cpi#cpis-with-pda-signers) [Anchor](https://solana.com/docs/core/cpi#anchor) [Rust](https://solana.com/docs/core/cpi#rust) [CPIs without PDA signers](https://solana.com/docs/core/cpi#cpis-without-pda-signers) [Anchor](https://solana.com/docs/core/cpi#anchor-1) [Rust](https://solana.com/docs/core/cpi#rust-1) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/cpi.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Cross Program Invocation | Solana --- # Rust SDK for Solana | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) Solana SDKsOfficial SDKs [Rust SDK for Solana](https://solana.com/docs/clients/official/rust) ===================================================================== Copy MarkdownOpen [Client Crates](https://solana.com/docs/clients/official/rust#client-crates) ----------------------------------------------------------------------------- | Crate | Description | Docs | GitHub | | --- | --- | --- | --- | | solana-sdk | Core SDK | [View](https://docs.rs/solana-sdk/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/sdk) | | solana-client | Interact with Solana via RPC | [View](https://docs.rs/solana-client/) | [Source](https://github.com/anza-xyz/agave/tree/master/client) | | solana-commitment-config | Transaction commitment level configuration | [View](https://docs.rs/solana-commitment-config/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/commitment-config) | The `solana-sdk` crate is composed of the following component crates, which can be used independently: | Crate | Description | Docs | GitHub | | --- | --- | --- | --- | | solana-account | Solana Account type | [View](https://docs.rs/solana-account/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/account) | | solana-epoch-info | Information about a Solana epoch | [View](https://docs.rs/solana-epoch-info/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/epoch-info) | | solana-epoch-rewards-hasher | Solana epoch rewards hasher | [View](https://docs.rs/solana-epoch-rewards-hasher/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/epoch-rewards-hasher) | | solana-fee-structure | Solana fee structures | [View](https://docs.rs/solana-fee-structure/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/fee-structure) | | solana-inflation | Configuration for Solana network inflation | [View](https://docs.rs/solana-inflation/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/inflation) | | solana-message | Solana transaction message types | [View](https://docs.rs/solana-message/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/message) | | solana-program | Solana Program | [View](https://docs.rs/solana-program/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/program) | | solana-program-memory | Basic low-level memory operations for Solana | [View](https://docs.rs/solana-program-memory/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/program-memory) | | solana-pubkey | Solana account addresses | [View](https://docs.rs/solana-pubkey/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/pubkey) | | solana-sanitize | Solana Message Sanitization | [View](https://docs.rs/solana-sanitize/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/sanitize) | | solana-sdk-ids | Solana SDK IDs | [View](https://docs.rs/solana-sdk-ids/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/sdk-ids) | | solana-sdk-macro | Solana SDK Macro | [View](https://docs.rs/solana-sdk-macro/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/sdk-macro) | | solana-serde | Solana serde helpers | [View](https://docs.rs/solana-serde/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/serde) | | solana-serde-varint | Solana definitions for integers that serialize to variable size | [View](https://docs.rs/solana-serde-varint/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/serde-varint) | | solana-short-vec | Solana compact serde-encoding of vectors with small length | [View](https://docs.rs/solana-short-vec/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/short-vec) | | solana-time-utils | std::time utilities for Solana | [View](https://docs.rs/solana-time-utils/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/time-utils) | | solana-keypair | Concrete implementation of a Solana Signer | [View](https://docs.rs/solana-keypair/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/keypair) | | solana-offchain-message | Solana offchain message signing | [View](https://docs.rs/solana-offchain-message/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/offchain-message) | | solana-presigner | A Solana Signer implementation representing an externally-constructed Signature | [View](https://docs.rs/solana-presigner/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/presigner) | | solana-seed-derivable | Solana trait defining the interface by which keys are derived | [View](https://docs.rs/solana-seed-derivable/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/seed-derivable) | | solana-seed-phrase | Solana functions for generating keypairs from seed phrases | [View](https://docs.rs/solana-seed-phrase/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/seed-phrase) | | solana-shred-version | Calculation of shred versions | [View](https://docs.rs/solana-shred-version/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/shred-version) | | solana-signature | Solana 64-byte signature type | [View](https://docs.rs/solana-signature/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/signature) | | solana-signer | Abstractions for Solana transaction signers | [View](https://docs.rs/solana-signer/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/signer) | | solana-transaction | Solana transaction-types | [View](https://docs.rs/solana-transaction/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/transaction) | | solana-transaction-error | Solana TransactionError type | [View](https://docs.rs/solana-transaction-error/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/transaction-error) | [Program Crates](https://solana.com/docs/clients/official/rust#program-crates) ------------------------------------------------------------------------------- Use `solana-program` to build on-chain programs. * [Example: Build a Solana program](https://solana.com/docs/programs/rust) | Crate | Description | Docs | GitHub | | --- | --- | --- | --- | | solana-program | Build on-chain programs | [View](https://docs.rs/solana-program) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/program) | Pinocchio is a zero-dependency library to create Solana programs in Rust and can be used as a replacement for `solana-program` to write on-chain programs. | Crate | Description | Docs | GitHub | | --- | --- | --- | --- | | pinocchio | Zero-dependency on-chain programs | [View](https://docs.rs/pinocchio) | [Source](https://github.com/anza-xyz/pinocchio) | Pinocchio is still in development and will likely have breaking changes in the near future. Pinocchio includes program-specific crates for interacting with Solana programs: | Crate | Description | Docs | GitHub | | --- | --- | --- | --- | | pinocchio-system | Interact with System program | [View](https://docs.rs/pinocchio-system/) | [Source](https://github.com/anza-xyz/pinocchio/tree/main/programs/system) | | pinocchio-token | Interact with Token program | [View](https://docs.rs/pinocchio-token/) | [Source](https://github.com/anza-xyz/pinocchio/tree/main/programs/token) | | pinocchio-token-2022 | Interact with Token-2022 program | [View](https://docs.rs/pinocchio-token-2022/) | [Source](https://github.com/anza-xyz/pinocchio/tree/main/programs/token-2022) | | pinocchio-associated-token-account | Interact with Associated Token program | [View](https://docs.rs/pinocchio-associated-token-account/) | [Source](https://github.com/anza-xyz/pinocchio/tree/main/programs/associated-token-account) | | pinocchio-memo | Interact with Memo program | [View](https://docs.rs/pinocchio-memo/) | [Source](https://github.com/anza-xyz/pinocchio/tree/main/programs/memo) | [Interface Crates](https://solana.com/docs/clients/official/rust#interface-crates) ----------------------------------------------------------------------------------- | Crate | Description | Docs | GitHub | | --- | --- | --- | --- | | solana-system-interface | Interact with System program | [View](https://docs.rs/solana-system-interface/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/system-interface) | | spl-token-interface | Interact with Token program | [View](https://docs.rs/spl-token-interface/) | [Source](https://github.com/solana-program/token/tree/main/interface) | | spl-token-2022-interface | Interact with Token-2022 program | [View](https://docs.rs/spl-token-2022-interface/) | [Source](https://github.com/solana-program/token-2022/tree/main/interface) | | spl-associated-token-account-interface | Interact with Associated Token program | [View](https://docs.rs/spl-associated-token-account-interface/) | [Source](https://github.com/solana-program/associated-token-account/tree/main/interface) | | solana-compute-budget-interface | Interact with Compute Budget program | [View](https://docs.rs/solana-compute-budget-interface/) | [Source](https://github.com/anza-xyz/solana-sdk/tree/master/compute-budget-interface) | | spl-memo-interface | Interact with Memo program | [View](https://docs.rs/spl-memo-interface/) | [Source](https://github.com/solana-program/memo/tree/main/interface) | | spl-token-metadata-interface | Interact with Token Metadata extension | [View](https://docs.rs/spl-token-metadata-interface/) | [Source](https://github.com/solana-program/token-metadata/tree/main/interface) | | spl-token-group-interface | Interact with Token Group extension | [View](https://docs.rs/spl-token-group-interface/) | [Source](https://github.com/solana-program/token-group/tree/main/interface) | Is this page helpful? [Previous\ \ Next.js + Solana React Hooks](https://solana.com/docs/frontend/nextjs-solana) [Next\ \ Typescript SDK](https://solana.com/docs/clients/official/javascript) ### Table of Contents [Client Crates](https://solana.com/docs/clients/official/rust#client-crates) [Program Crates](https://solana.com/docs/clients/official/rust#program-crates) [Interface Crates](https://solana.com/docs/clients/official/rust#interface-crates) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/clients/official/rust.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Rust SDK for Solana | Solana --- # Transactions | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Transactions](https://solana.com/docs/core/transactions) ========================================================== Copy MarkdownOpen To interact with the Solana network, you must send a transaction. You can think of a transaction as an envelope that holds several forms. Each form is an instruction that tells the network what to do. Sending the transaction is like mailing the envelope so the forms can be processed. The example below shows a simplified version of two transactions. When the first transaction is processed, it will execute a single instruction. When the second transaction is processed, it will execute three instructions **in sequential order**: first instruction 1, followed by instruction 2, followed by instruction 3. Transactions are **atomic**: If a single instruction fails, the entire transaction will fail and no changes will occur. A simplified diagram showing two transactions A [`Transaction`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/src/transaction/mod.rs#L207) consists of the following information: * `signatures`: An array of [signatures](https://solana.com/docs/core/transactions#signatures) * `message`: Transaction information, including the list of instructions to be processed Transaction pub struct Transaction { #\[wasm\_bindgen(skip)\] #\[serde(with \= "short\_vec")\] pub signatures: Vec, #\[wasm\_bindgen(skip)\] pub message: Message, } Diagram showing the two parts of a transaction Transactions have a total size limit of [1232](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/packet/src/lib.rs#L29) bytes. This limit includes both the [`signatures`](https://solana.com/docs/core/transactions#signatures) array and the [`message`](https://solana.com/docs/core/transactions#message) struct. This limit is designed to avoid packet fragmentation on typical internet infrastructure. While IPv6 supports MTUs larger than 9000 bytes, most internet routers use a default MTU of 1500 bytes (standard Ethernet). To ensure transactions fit within a single packet without fragmentation, Solana uses 1280 bytes (the minimum MTU required for IPv6) minus 48 bytes for network headers (40 bytes IPv6 + 8 bytes fragment/UDP header), resulting in the 1232 byte transaction size limit. Diagram showing the transaction format and size limits [Signatures](https://solana.com/docs/core/transactions#signatures) ------------------------------------------------------------------- The transaction's `signatures` array contains `Signature` structs. Each [`Signature`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/signature/src/lib.rs#L30) is 64 bytes and is created by signing the transaction's `Message` with the account's private key. A signature must be provided for each [signer account](https://solana.com/docs/core/transactions#account-addresses) included on any of the transaction's instructions. The first signature belongs to the account that will pay the transaction's [base fee](https://solana.com/docs/core/docs/core/fees#base-fee) and is the transaction signature. The transaction signature can be used to look up the transaction's details on the network. [Message](https://solana.com/docs/core/transactions#message) ------------------------------------------------------------- The transaction's `message` is a [`Message`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/message/legacy.rs#L131) struct that contains the following information: * `header`: The message [header](https://solana.com/docs/core/transactions#header) * `account_keys`: An array of [account addresses](https://solana.com/docs/core/transactions#account-addresses) required by the transaction's instructions * `recent_blockhash`: A [blockhash](https://solana.com/docs/core/transactions#recent-blockhash) that acts as a timestamp for the transaction * `instructions`: An array of [instructions](https://solana.com/docs/core/transactions#instructions) To save space, the transaction does not store permissions for each account individually. Instead, account permissions are determined using the `header` and `account_keys`. Message pub struct Message { /// The message header, identifying signed and read-only \`account\_keys\`. pub header: MessageHeader, /// All the account keys used by this transaction. #\[serde(with \= "short\_vec")\] pub account\_keys: Vec, /// The id of a recent ledger entry. pub recent\_blockhash: Hash, /// Programs that will be executed in sequence and committed in /// one atomic transaction if all succeed. #\[serde(with \= "short\_vec")\] pub instructions: Vec, } The message's `header` is a [`MessageHeader`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/message/mod.rs#L97) struct. It contains the following information: * `num_required_signatures`: The total number of signatures required by the transaction * `num_readonly_signed_accounts`: The total number of read-only accounts that require signatures * `num_readonly_unsigned_accounts`: The total number of read-only accounts that don't require signatures MessageHeader pub struct MessageHeader { /// The number of signatures required for this message to be considered /// valid. The signers of those signatures must match the first /// \`num\_required\_signatures\` of \[\`Message::account\_keys\`\]. pub num\_required\_signatures: u8, /// The last \`num\_readonly\_signed\_accounts\` of the signed keys are read-only /// accounts. pub num\_readonly\_signed\_accounts: u8, /// The last \`num\_readonly\_unsigned\_accounts\` of the unsigned keys are /// read-only accounts. pub num\_readonly\_unsigned\_accounts: u8, } Diagram showing the three parts of the message header ### [Account addresses](https://solana.com/docs/core/transactions#account-addresses) The message's [`account_keys`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/message/legacy.rs#L138) is an array of account addresses, sent in [compact array format](https://solana.com/docs/references/terminology#compact-array-format) . The array's prefix indicates its length. Each item in the array is a public key, pointing to an account used by its instructions. The `accounts_keys` array must be complete, and strictly ordered, as follows: 1. Signer + Writable 2. Signer + Read-only 3. Not signer + Writable 4. Not signer + Read-only Strict ordering allows the `account_keys` array to be combined with the information in the message's [`header`](https://solana.com/docs/core/transactions#header) to determine the permissions for each account. Diagram showing the order of the account addresses array ### [Recent blockhash](https://solana.com/docs/core/transactions#recent-blockhash) The message's `recent_blockhash` is a hash value that acts as a transaction timestamp and prevents duplicate transactions. A blockhash expires after [150 blocks](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/clock/src/lib.rs#L134) . (Equivalent to one minute—assuming each block is 400ms.) After the block expires, the transaction is expired and cannot be processed. The [`getLatestBlockhash`](https://solana.com/docs/rpc/http/getlatestblockhash) RPC method allows you to get the current blockhash and last block height at which the blockhash will be valid. ### [Instructions](https://solana.com/docs/core/transactions#instructions) The message's [`instructions`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/message/legacy.rs#L146) is an array of all the instructions to be processed, sent in [compact array format](https://solana.com/docs/references/terminology#compact-array-format) . The array's prefix indicates its length. Each item in the array is a [`CompiledInstruction`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/instruction.rs#L22) struct and includes the following information: 1. `program_id_index`: An index pointing to an address in the [`account_keys`](https://solana.com/docs/core/transactions#account-addresses) array. This value indicates the address of the program that processes the instruction. 2. `accounts`: An array of indices pointing to addresses in the `account_keys` array. Each index points to the address of an account required for this instruction. 3. `data`: A byte array specifying which instruction to invoke on the program. It also includes any additional data required by the instruction. (For example, function arguments) CompiledInstruction pub struct CompiledInstruction { /// Index into the transaction keys array indicating the program account that executes this instruction. pub program\_id\_index: u8, /// Ordered indices into the transaction keys array indicating which accounts to pass to the program. #\[serde(with \= "short\_vec")\] pub accounts: Vec, /// The program input data. #\[serde(with \= "short\_vec")\] pub data: Vec, } Compact array of Instructions [Example transaction structure](https://solana.com/docs/core/transactions#example-transaction-structure) --------------------------------------------------------------------------------------------------------- The following example shows the structure of a transaction that contains a single SOL transfer instruction. Kit Legacy Rust import { createSolanaRpc, generateKeyPairSigner, lamports, createTransactionMessage, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, pipe, signTransactionMessageWithSigners, getCompiledTransactionMessageDecoder } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; const rpc \= createSolanaRpc("http://localhost:8899"); const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Generate sender and recipient keypairs const sender \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); // Define the amount to transfer const LAMPORTS\_PER\_SOL \= 1\_000\_000\_000n; const transferAmount \= lamports(LAMPORTS\_PER\_SOL / 100n); // 0.01 SOL // Create a transfer instruction for transferring SOL from sender to recipient const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount }); // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(sender, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[transferInstruction\], tx) ); const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Decode the messageBytes const compiledTransactionMessage \= getCompiledTransactionMessageDecoder().decode(signedTransaction.messageBytes); console.log(JSON.stringify(compiledTransactionMessage, null, 2)); Console RunClick to execute the code. Kit Legacy Rust import { createSolanaRpc, generateKeyPairSigner, lamports, createTransactionMessage, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, pipe, signTransactionMessageWithSigners, getCompiledTransactionMessageDecoder } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; const rpc \= createSolanaRpc("http://localhost:8899"); const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Generate sender and recipient keypairs const sender \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); // Define the amount to transfer const LAMPORTS\_PER\_SOL \= 1\_000\_000\_000n; const transferAmount \= lamports(LAMPORTS\_PER\_SOL / 100n); // 0.01 SOL // Create a transfer instruction for transferring SOL from sender to recipient const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount }); // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(sender, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[transferInstruction\], tx) ); const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Decode the messageBytes const compiledTransactionMessage \= getCompiledTransactionMessageDecoder().decode(signedTransaction.messageBytes); console.log(JSON.stringify(compiledTransactionMessage, null, 2)); Console RunClick to execute the code. The code below shows the output from the previous code snippets. The format differs between SDKs, but notice that each instruction contains the same required information. Kit Legacy Rust { "version": 0, "header": { "numSignerAccounts": 1, "numReadonlySignerAccounts": 0, "numReadonlyNonSignerAccounts": 1 }, "staticAccounts": \[\ \ "HoCy8p5xxDDYTYWEbQZasEjVNM5rxvidx8AfyqA4ywBa",\ \ "5T388jBjovy7d8mQ3emHxMDTbUF8b7nWvAnSiP3EAdFL",\ \ "11111111111111111111111111111111"\ \ \], "lifetimeToken": "EGCWPUEXhqHJWYBfDirq3mHZb4qDpATmYqBZMBy9TBC1", "instructions": \[\ \ {\ \ "programAddressIndex": 2,\ \ "accountIndices": \[0, 1\],\ \ "data": {\ \ "0": 2,\ \ "1": 0,\ \ "2": 0,\ \ "3": 0,\ \ "4": 128,\ \ "5": 150,\ \ "6": 152,\ \ "7": 0,\ \ "8": 0,\ \ "9": 0,\ \ "10": 0,\ \ "11": 0\ \ }\ \ }\ \ \] } After a transaction is submitted, you can retrieve its details using the transaction signature and the [getTransaction](https://solana.com/docs/rpc/http/gettransaction) RPC method. The response will have a structure similar to the following snippet. You can also find the transaction using [Solana Explorer](https://explorer.solana.com/) . Transaction Data { "blockTime": 1745196488, "meta": { "computeUnitsConsumed": 150, "err": null, "fee": 5000, "innerInstructions": \[\], "loadedAddresses": { "readonly": \[\], "writable": \[\] }, "logMessages": \[\ \ "Program 11111111111111111111111111111111 invoke \[1\]",\ \ "Program 11111111111111111111111111111111 success"\ \ \], "postBalances": \[989995000, 10000000, 1\], "postTokenBalances": \[\], "preBalances": \[1000000000, 0, 1\], "preTokenBalances": \[\], "rewards": \[\], "status": { "Ok": null } }, "slot": 13049, "transaction": { "message": { "header": { "numReadonlySignedAccounts": 0, "numReadonlyUnsignedAccounts": 1, "numRequiredSignatures": 1 }, "accountKeys": \[\ \ "8PLdpLxkuv9Nt8w3XcGXvNa663LXDjSrSNon4EK7QSjQ",\ \ "7GLg7bqgLBv1HVWXKgWAm6YoPf1LoWnyWGABbgk487Ma",\ \ "11111111111111111111111111111111"\ \ \], "recentBlockhash": "7ZCxc2SDhzV2bYgEQqdxTpweYJkpwshVSDtXuY7uPtjf", "instructions": \[\ \ {\ \ "accounts": \[0, 1\],\ \ "data": "3Bxs4NN8M2Yn4TLb",\ \ "programIdIndex": 2,\ \ "stackHeight": null\ \ }\ \ \], "indexToProgramIds": {} }, "signatures": \[\ \ "3jUKrQp1UGq5ih6FTDUUt2kkqUfoG2o4kY5T1DoVHK2tXXDLdxJSXzuJGY4JPoRivgbi45U2bc7LZfMa6C4R3szX"\ \ \] }, "version": "legacy" } Is this page helpful? [Previous\ \ Instructions](https://solana.com/docs/core/instructions) [Next\ \ Transaction Fees](https://solana.com/docs/core/fees) ### Table of Contents [Signatures](https://solana.com/docs/core/transactions#signatures) [Message](https://solana.com/docs/core/transactions#message) [Header](https://solana.com/docs/core/transactions#header) [Account addresses](https://solana.com/docs/core/transactions#account-addresses) [Recent blockhash](https://solana.com/docs/core/transactions#recent-blockhash) [Instructions](https://solana.com/docs/core/transactions#instructions) [Example transaction structure](https://solana.com/docs/core/transactions#example-transaction-structure) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/transactions.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Transactions | Solana --- # Accounts | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Accounts](https://solana.com/docs/core/accounts) ================================================== Copy MarkdownOpen All data on the Solana network is stored in accounts. You can think of the Solana network as a public database with a single Accounts table. The relationship between an account and its address is similar to that of a key-value pair, with the key being the address and the value being the account. Each account has the same basic [structure](https://solana.com/docs/core/accounts#account-structure) and can be located using its [address](https://solana.com/docs/core/accounts#account-address) . Diagram of 3 accounts and their addresses. Includes the account structure definition. [Account address](https://solana.com/docs/core/accounts#account-address) ------------------------------------------------------------------------- The account's address is a 32-byte unique ID used to locate the account on the Solana blockchain. Account addresses are often shown as base58 encoded strings. Most accounts use an [Ed25519](https://ed25519.cr.yp.to/) [public key](https://solana.com/docs/core/accounts#public-key) as their address, but this is not required, as Solana also supports [program derived addresses](https://solana.com/docs/core/accounts#program-derived-address) . An account with its base58 encoded public key address ### [Public key](https://solana.com/docs/core/accounts#public-key) The example below demonstrates how to use the Solana SDK to create a keypair. A `Keypair` includes: * A public key which serves as the account address * A private key which is used to sign transactions Kit Legacy Rust import { generateKeyPairSigner } from "@solana/kit"; // Kit does not enable extractable private keys const keypairSigner \= await generateKeyPairSigner(); console.log(keypairSigner); Console RunClick to execute the code. Kit Legacy Rust import { generateKeyPairSigner } from "@solana/kit"; // Kit does not enable extractable private keys const keypairSigner \= await generateKeyPairSigner(); console.log(keypairSigner); Console RunClick to execute the code. ### [Program derived address](https://solana.com/docs/core/accounts#program-derived-address) A [program derived address](https://solana.com/docs/core/pda) (PDA) is an address that is deterministically derived using a program ID and one or more optional inputs (seeds). The example below demonstrates how to use the Solana SDK to create a program derived address. Kit Legacy Rust import { Address, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const seeds \= \["helloWorld"\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. Kit Legacy Rust import { Address, getProgramDerivedAddress } from "@solana/kit"; const programAddress \= "11111111111111111111111111111111" as Address; const seeds \= \["helloWorld"\]; const \[pda, bump\] \= await getProgramDerivedAddress({ programAddress, seeds }); console.log(\`PDA: ${pda}\`); console.log(\`Bump: ${bump}\`); Console RunClick to execute the code. [Account structure](https://solana.com/docs/core/accounts#account-structure) ----------------------------------------------------------------------------- Every [`Account`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/account/src/lib.rs#L48-L60) has a maximum size of [10MiB](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/program/src/system_instruction.rs#L85) and contains following information: * `lamports`: The number of lamports in the account * `data`: The account's data * `owner`: The ID of the program that owns the account * `executable`: Indicates whether the account contains executable binary * `rent_epoch`: The deprecated rent epoch field Account pub struct Account { /// lamports in the account pub lamports: u64, /// data held in this account #\[cfg\_attr(feature \= "serde", serde(with \= "serde\_bytes"))\] pub data: Vec, /// the program that owns this account. If executable, the program that loads this account. pub owner: Pubkey, /// this account's data contains a loaded program (and is now read-only) pub executable: bool, /// the epoch at which this account will next owe rent pub rent\_epoch: Epoch, } Lamports -------- The account's balance in [lamports](https://solana.com/docs/references/terminology#lamport) . Every account must have a minimum lamport balance, called [rent](https://solana.com/docs/references/terminology#rent) , which allows its data to be stored on-chain. Rent is proportional to the size of the account. Although this balance is called rent, it works more like a deposit, as the full balance can be recovered when the account is closed. (The name "rent" comes from the now deprecated rent epoch field.) (See the [minimum balance](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/rent/src/lib.rs#L93-L97) formula and the applicable [constants](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/rent/src/lib.rs#L47-L70) .) Data ---- This field is commonly referred to as "account data". The `data` in this field is considered arbitrary as it can contain any sequence of bytes. Each program defines the structure of the data stored in this field. * Program accounts: This field contains either executable program code or the address of a [program data account](https://solana.com/docs/core/accounts#program-data-accounts) which stores the executable program code. * Data accounts: This field generally stores state data, meant to be read. Reading data from a Solana account involves two steps: 1. Fetching the account using its [address](https://solana.com/docs/core/accounts#account-address) 2. Deserializing the account's `data` field from raw bytes into the appropriate data structure, as defined by the program that owns the account. Owner ----- This field contains the program ID of the account's owner. Every Solana account has a [program](https://solana.com/docs/core/programs) designated as its owner. The account's owner is the only program that can change the account's `data` or deduct lamports, as indicated by the program's instructions. (In the case of a program account, the owner is its [loader program](https://solana.com/docs/core/programs#loader-programs) .) Executable ---------- This field indicates whether an account is a [program account](https://solana.com/docs/core/accounts#program-accounts) or a [data account](https://solana.com/docs/core/accounts#data-accounts) * If `true`: The account is a program account * If `false`: The account is a data account Rent epoch ---------- **The `rent_epoch` field is deprecated.** In the past, this field tracked when an account would need to pay rent. However, this rent collection mechanism has since been deprecated. Lamports -------- The account's balance in [lamports](https://solana.com/docs/references/terminology#lamport) . Every account must have a minimum lamport balance, called [rent](https://solana.com/docs/references/terminology#rent) , which allows its data to be stored on-chain. Rent is proportional to the size of the account. Although this balance is called rent, it works more like a deposit, as the full balance can be recovered when the account is closed. (The name "rent" comes from the now deprecated rent epoch field.) (See the [minimum balance](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/rent/src/lib.rs#L93-L97) formula and the applicable [constants](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/rent/src/lib.rs#L47-L70) .) Data ---- This field is commonly referred to as "account data". The `data` in this field is considered arbitrary as it can contain any sequence of bytes. Each program defines the structure of the data stored in this field. * Program accounts: This field contains either executable program code or the address of a [program data account](https://solana.com/docs/core/accounts#program-data-accounts) which stores the executable program code. * Data accounts: This field generally stores state data, meant to be read. Reading data from a Solana account involves two steps: 1. Fetching the account using its [address](https://solana.com/docs/core/accounts#account-address) 2. Deserializing the account's `data` field from raw bytes into the appropriate data structure, as defined by the program that owns the account. Owner ----- This field contains the program ID of the account's owner. Every Solana account has a [program](https://solana.com/docs/core/programs) designated as its owner. The account's owner is the only program that can change the account's `data` or deduct lamports, as indicated by the program's instructions. (In the case of a program account, the owner is its [loader program](https://solana.com/docs/core/programs#loader-programs) .) Executable ---------- This field indicates whether an account is a [program account](https://solana.com/docs/core/accounts#program-accounts) or a [data account](https://solana.com/docs/core/accounts#data-accounts) * If `true`: The account is a program account * If `false`: The account is a data account Rent epoch ---------- **The `rent_epoch` field is deprecated.** In the past, this field tracked when an account would need to pay rent. However, this rent collection mechanism has since been deprecated. Account Examples // Example Token Mint Account Account { lamports: 1461600, data.len: 82, owner: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb, executable: false, rent\_epoch: 0, data: 010000001e213c90625a7e643d9555bb01b6c3fe6416d7afd523ce8c7ddd9b923ceafb9d00000000000000000901010000001e213c90625a7e643d9555bb01b6, } // Example Token Program Account Account { lamports: 4513200894, data.len: 134080, owner: BPFLoader2111111111111111111111111111111111, executable: true, rent\_epoch: 18446744073709551615, data: 7f454c460201010000000000000000000300f70001000000d8f90000000000004000000000000000800902000000000000000000400038000400400009000800, } [Types of accounts](https://solana.com/docs/core/accounts#types-of-accounts) ----------------------------------------------------------------------------- There are two basic categories that accounts fall into: * [Program accounts](https://solana.com/docs/core/accounts#program-accounts) : Accounts that contain executable code * [Data accounts](https://solana.com/docs/core/accounts#data-accounts) : Accounts that do not contain executable code This separation of a program's code and its state is a key feature of Solana's account model. (Similar to operating systems, which typically have separate files for programs and their data.) ### [Program accounts](https://solana.com/docs/core/accounts#program-accounts) Every program is owned by a [loader program](https://solana.com/docs/core/programs#loader-programs) , which is used to deploy and manage the account. When a new [program](https://solana.com/docs/core/programs) is deployed, an account is created to store its [executable](https://solana.com/docs/core/accounts#executable) code. This is called a program account. (For simplicity, you can consider the program account to be the program itself.) In the diagram below, you can see a loader program is used to deploy a program account. The program account's `data` contains the executable program code. Diagram of a program account, its 4 component and its loader program. #### [Program data accounts](https://solana.com/docs/core/accounts#program-data-accounts) Programs deployed using loader-v3 do not contain program code in their `data` field. Instead, their `data` points to a separate **program data account**, which contains the program code. (See the diagram below.) A program account with data. The data points to a separate program data account During program deployment or upgrades, buffer accounts are used to temporarily stage the upload. The example below fetches the Token Program account. Notice that the `executable` field is set to `true`, indicating the account is a program. Kit Legacy Rust import { Address, createSolanaRpc } from "@solana/kit"; const rpc \= createSolanaRpc("https://api.mainnet.solana.com"); const programId \= "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address; const accountInfo \= await rpc .getAccountInfo(programId, { encoding: "base64" }) .send(); console.log(accountInfo); Console RunClick to execute the code. Kit Legacy Rust import { Address, createSolanaRpc } from "@solana/kit"; const rpc \= createSolanaRpc("https://api.mainnet.solana.com"); const programId \= "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address; const accountInfo \= await rpc .getAccountInfo(programId, { encoding: "base64" }) .send(); console.log(accountInfo); Console RunClick to execute the code. ### [Data accounts](https://solana.com/docs/core/accounts#data-accounts) Data accounts do not contain executable code. Instead, they store information. #### [Program state account](https://solana.com/docs/core/accounts#program-state-account) Programs use data accounts to maintain their state. To do so, they must first create a new data account. The process of creating a program state account is often abstracted, but it is helpful to understand the underlying process. To manage its state, a new program must: 1. Invoke the [System Program](https://solana.com/docs/core/programs#the-system-program) to create an account. (The System Program then transfers ownership to the new program.) 2. Initialize the account data, as defined by its [instructions](https://solana.com/docs/core/instructions) . Diagram of a data account owned by a program account The example below creates and fetches a Token Mint account owned by the Token 2022 program. Kit Legacy Rust import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getInitializeMintInstruction, getMintSize, TOKEN\_2022\_PROGRAM\_ADDRESS, fetchMint } from "@solana-program/token-2022"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Instruction to create new account for mint (token 2022 program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_2022\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token 2022 program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and mint keypair) const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address); console.log("Transaction Signature:", transactionSignature); const accountInfo \= await rpc.getAccountInfo(mint.address).send(); console.log(accountInfo); const mintAccount \= await fetchMint(rpc, mint.address); console.log(mintAccount); Console RunClick to execute the code. Kit Legacy Rust import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getInitializeMintInstruction, getMintSize, TOKEN\_2022\_PROGRAM\_ADDRESS, fetchMint } from "@solana-program/token-2022"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Instruction to create new account for mint (token 2022 program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_2022\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token 2022 program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and mint keypair) const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address); console.log("Transaction Signature:", transactionSignature); const accountInfo \= await rpc.getAccountInfo(mint.address).send(); console.log(accountInfo); const mintAccount \= await fetchMint(rpc, mint.address); console.log(mintAccount); Console RunClick to execute the code. #### [System accounts](https://solana.com/docs/core/accounts#system-accounts) Not all accounts are assigned a new owner after being created by the System Program. Accounts owned by the System Program are called system accounts. All wallet accounts are system accounts, which allows them to pay [transaction fees](https://solana.com/docs/core/docs/core/fees) . A wallet owned by the System Program containing 1,000,000 lamports When SOL is sent to a new address for the first time, an account is created at that address owned by the System Program. In the example below, a new keypair is generated and funded with SOL. After running the code, you can see the address of the account's `owner` is `11111111111111111111111111111111` (the [System Program](https://solana.com/docs/core/programs#the-system-program) ). Kit Legacy Rust import { airdropFactory, createSolanaRpc, createSolanaRpcSubscriptions, generateKeyPairSigner, lamports } from "@solana/kit"; // Create a connection to Solana cluster const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate a new keypair const keypair \= await generateKeyPairSigner(); console.log(\`Public Key: ${keypair.address}\`); // Funding an address with SOL automatically creates an account const signature \= await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: keypair.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); const accountInfo \= await rpc.getAccountInfo(keypair.address).send(); console.log(accountInfo); Console RunClick to execute the code. Kit Legacy Rust import { airdropFactory, createSolanaRpc, createSolanaRpcSubscriptions, generateKeyPairSigner, lamports } from "@solana/kit"; // Create a connection to Solana cluster const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate a new keypair const keypair \= await generateKeyPairSigner(); console.log(\`Public Key: ${keypair.address}\`); // Funding an address with SOL automatically creates an account const signature \= await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: keypair.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); const accountInfo \= await rpc.getAccountInfo(keypair.address).send(); console.log(accountInfo); Console RunClick to execute the code. #### [Sysvar accounts](https://solana.com/docs/core/accounts#sysvar-accounts) Sysvar accounts exist at predefined addresses and provide access to cluster state data. They update dynamically with data about the network cluster. See the full list of [Sysvar Accounts](https://docs.anza.xyz/runtime/sysvars) . The example below fetches and deserializes data from the Sysvar Clock account. Kit Legacy Rust import { createSolanaRpc } from "@solana/kit"; import { fetchSysvarClock, SYSVAR\_CLOCK\_ADDRESS } from "@solana/sysvars"; const rpc \= createSolanaRpc("https://api.mainnet.solana.com"); const accountInfo \= await rpc .getAccountInfo(SYSVAR\_CLOCK\_ADDRESS, { encoding: "base64" }) .send(); console.log(accountInfo); // Automatically fetch and deserialize the account data const clock \= await fetchSysvarClock(rpc); console.log(clock); Console RunClick to execute the code. Kit Legacy Rust import { createSolanaRpc } from "@solana/kit"; import { fetchSysvarClock, SYSVAR\_CLOCK\_ADDRESS } from "@solana/sysvars"; const rpc \= createSolanaRpc("https://api.mainnet.solana.com"); const accountInfo \= await rpc .getAccountInfo(SYSVAR\_CLOCK\_ADDRESS, { encoding: "base64" }) .send(); console.log(accountInfo); // Automatically fetch and deserialize the account data const clock \= await fetchSysvarClock(rpc); console.log(clock); Console RunClick to execute the code. Is this page helpful? [Previous\ \ Core Concepts](https://solana.com/docs/core) [Next\ \ Instructions](https://solana.com/docs/core/instructions) ### Table of Contents [Account address](https://solana.com/docs/core/accounts#account-address) [Public key](https://solana.com/docs/core/accounts#public-key) [Program derived address](https://solana.com/docs/core/accounts#program-derived-address) [Account structure](https://solana.com/docs/core/accounts#account-structure) [Types of accounts](https://solana.com/docs/core/accounts#types-of-accounts) [Program accounts](https://solana.com/docs/core/accounts#program-accounts) [Program data accounts](https://solana.com/docs/core/accounts#program-data-accounts) [Data accounts](https://solana.com/docs/core/accounts#data-accounts) [Program state account](https://solana.com/docs/core/accounts#program-state-account) [System accounts](https://solana.com/docs/core/accounts#system-accounts) [Sysvar accounts](https://solana.com/docs/core/accounts#sysvar-accounts) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/accounts.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Accounts | Solana --- # Frontend | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) [Frontend](https://solana.com/docs/frontend) ============================================= Copy MarkdownOpen Frontend development on Solana involves working with Programs, wallets and popular JavaScript frameworks like React. Interacting with these components requires handling connection, transaction creation and reading from Solana Accounts. To help with this work, a variety Solana Client libraries are available in different frameworks. [Main libraries](https://solana.com/docs/frontend#main-libraries) ------------------------------------------------------------------ [### @solana/client\ \ * Simple Solana client bundling RPC, wallets, transactions\ * Includes built-in state store, actions, watchers, connectors](https://github.com/solana-foundation/framework-kit/tree/main/packages/client) [### @solana/react-hooks\ \ * Complete hooks for wallets, balances, transfers, signatures, queries\ * React provider hooks wrapping `@solana/client` runtime state](https://github.com/solana-foundation/framework-kit/tree/main/packages/react-hooks) [### @solana/web3-compat\ \ * Web3.js compatible toolkit to simplify upgrading.\ * Newer internals relying on a mix of web3.js and kit.](https://github.com/solana-foundation/framework-kit/tree/main/packages/web3-compat) [### @solana/kit\ \ * Low level Solana SDK powering the other Solana libraries like `@solana/react-hooks`\ * Fully tree-shakable, uses modern web standards, and powers the runtime](https://github.com/solana-foundation/framework-kit/tree/main/packages/kit) @solana/web3.js is deprecated\` Many Solana ecosystem projects still rely on the deprecated `@solana/web3.js`. Prefer `@solana/web3-compat` to simplify your migration path. * [@solana/client guide](https://solana.com/docs/frontend/client) : lean, headless runtime for RPC, wallets, and transactions. * [@solana/react-hooks guide](https://solana.com/docs/frontend/react-hooks) : React hooks layered on the same client runtime. * [@solana/web3-compat guide](https://solana.com/docs/frontend/web3-compat) : compatibility layer to migrate from `@solana/web3.js` to Kit powered stacks. Is this page helpful? [Previous\ \ Limitations](https://solana.com/docs/programs/limitations) [Next\ \ @solana/client](https://solana.com/docs/frontend/client) ### Table of Contents [Main libraries](https://solana.com/docs/frontend#main-libraries) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/frontend/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Frontend | Solana --- # Install the Solana CLI and Anchor with one command | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) Getting Started [Quick Installation](https://solana.com/docs/intro/installation) ================================================================= Copy MarkdownOpen A quick installation to set up your local Solana development environment with one command. Install Rust, the Solana CLI, and Anchor Framework on Windows (WSL), Linux, and Mac. (If preferred, you may [install each dependency individually](https://solana.com/docs/intro/installation/dependencies) .) [Prerequisites](https://solana.com/docs/intro/installation#prerequisites) -------------------------------------------------------------------------- ### Windows ### Linux [Installation](https://solana.com/docs/intro/installation#installation) ------------------------------------------------------------------------ 1. Enter the following command into your terminal to install all the necessary dependencies: Terminal $ curl --proto '=https' --tlsv1.2 -sSfL https://solana-install.solana.workers.dev | bash Copy A successful installation will return output like the following: Example output Installed Versions: Rust: rustc 1.91.1 (ed61e7d7e 2025-11-07) Solana CLI: solana-cli 3.0.10 (src:96c3a851; feat:3604001754, client:Agave) Anchor CLI: anchor-cli 0.32.1 Surfpool CLI: surfpool 0.12.0 Node.js: v24.10.0 Yarn: 1.22.1 2. Verify a successful installation by checking the version of each installed dependency. Terminal $ rustc --version && solana --version && anchor --version && surfpool --version && node --version && yarn --version Copy If the quick installation command fails, please refer to the [Install Dependencies](https://solana.com/docs/intro/installation/dependencies) section below for instructions to install each dependency individually. Is this page helpful? [Next\ \ Install Dependencies](https://solana.com/docs/intro/installation/dependencies) ### Table of Contents [Prerequisites](https://solana.com/docs/intro/installation#prerequisites) [Installation](https://solana.com/docs/intro/installation#installation) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/installation/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Install the Solana CLI and Anchor with one command | Solana --- # Programs | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Programs](https://solana.com/docs/core/programs) ================================================== Copy MarkdownOpen On Solana, a smart contract is called a program. A program is a stateless [account](https://solana.com/docs/core/accounts#program-account) that contains executable code. This code is organized into functions called instructions. Users interact with a program by sending a [transaction](https://solana.com/docs/core/transactions) containing one or more [instructions](https://solana.com/docs/core/instructions) . A transaction can include instructions from multiple programs. When a program is deployed, Solana uses [LLVM](https://llvm.org/) to compile it into executable and linkable format ([ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) ). The ELF file contains the program's binary in Solana Bytecode Format (sBPF) and is saved on-chain in an executable account. sBPF is Solana's custom version of [eBPF](https://en.wikipedia.org/wiki/EBPF) bytecode. [Write programs](https://solana.com/docs/core/programs#write-programs) ----------------------------------------------------------------------- The majority of programs are written in [Rust](https://rust-book.cs.brown.edu/title-page.html) , with two common development approaches: * [Anchor](https://www.anchor-lang.com/docs) : Anchor is a framework designed for fast and easy Solana development. It uses [Rust macros](https://doc.rust-lang.org/book/ch20-05-macros.html) to reduce boilerplate code—making it great for beginners. * [Native Rust](https://solana.com/docs/programs/rust) : Write programs in Rust without leveraging any frameworks. This approach offers more flexibility but comes with increased complexity. [Update programs](https://solana.com/docs/core/programs#update-programs) ------------------------------------------------------------------------- To [modify](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/bpf_loader/src/lib.rs#L704) an existing program, an account must be designated as the [upgrade authority](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/bpf_loader/src/lib.rs#L894) . (Typically the same account that originally [deployed the program](https://solana.com/docs/programs/deploying) .) If the upgrade authority is revoked and set to `None`, the program can no longer be updated. [Verify programs](https://solana.com/docs/core/programs#verify-programs) ------------------------------------------------------------------------- Solana supports [verifiable builds](https://solana.com/docs/programs/verified-builds) , which allow users to check whether a program's on-chain code matches its public source code. The Anchor framework provides [built-in support](https://www.anchor-lang.com/docs/verifiable-builds) for creating a verifiable build. To check whether an existing program is verified, search for its program ID on the [Solana Explorer](https://explorer.solana.com/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY) . Alternatively, you may use the Ellipsis Labs [Solana Verifiable Build CLI](https://github.com/Ellipsis-Labs/solana-verifiable-build) , to independently verify on-chain programs. [Built-in programs](https://solana.com/docs/core/programs#built-in-programs) ----------------------------------------------------------------------------- ### [The System Program](https://solana.com/docs/core/programs#the-system-program) The System Program is the only account that can create new accounts. By default, all new accounts are owned by the [System Program](https://github.com/anza-xyz/agave/tree/v2.1.13/programs/system/src) , although many are assigned a new owner upon creation. The System Program performs the following key functions: | Function | Description | | --- | --- | | [New Account Creation](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/system/src/system_processor.rs#L146) | Only the System Program can create new accounts. | | [Space Allocation](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/system/src/system_processor.rs#L71) | Sets the byte capacity for the data field of each account. | | [Assign Program Ownership](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/system/src/system_processor.rs#L113) | Once the System Program creates an account, it can reassign the designated program owner to a different program account. That's how custom programs take ownership of new accounts created by the System Program. | | [Transfer SOL](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/system/src/system_processor.rs#L215) | Transfers lamports (SOL) from System Accounts to other accounts. | The address of the system program is `11111111111111111111111111111111`. ### [Loader programs](https://solana.com/docs/core/programs#loader-programs) Every program is owned by another—its loader. Loaders are used to deploy, redeploy, upgrade or close programs. They are also used to finalize a program and transfer program authority. Loader programs are sometimes referred to as, 'BPF Loaders'. There are currently five loader programs, as shown in the table below. | Loader | Program ID | Notes | Instructions Link | | --- | --- | --- | --- | | native | `NativeLoader1111111111111111111111111111111` | Owns the other four loaders | — | | v1 | `BPFLoader1111111111111111111111111111111111` | Management instructions are disabled, but programs still execute | — | | v2 | `BPFLoader2111111111111111111111111111111111` | Management instructions are disabled, but programs still execute | [Instructions](https://docs.rs/solana-loader-v2-interface/latest/solana_loader_v2_interface/enum.LoaderInstruction.html) | | v3 | `BPFLoaderUpgradeab1e11111111111111111111111` | Programs can be updated after deployment. Program executable is stored in a separate program data account | [Instructions](https://docs.rs/solana-loader-v3-interface/latest/solana_loader_v3_interface/instruction/enum.UpgradeableLoaderInstruction.html) | | v4 | `LoaderV411111111111111111111111111111111111` | In development (unreleased) | [Instructions](https://docs.rs/solana-loader-v4-interface/latest/solana_loader_v4_interface/instruction/enum.LoaderV4Instruction.html) | Programs deployed with loader-v3 or loader-v4 may be modifiable after deployment, as determined by its upgrade authority. When a new program is deployed, the latest loader version will be used by default. ### [Precompiled programs](https://solana.com/docs/core/programs#precompiled-programs) In addition to the loader programs, Solana provides the following precompiled programs. #### [Verify ed25519 signature](https://solana.com/docs/core/programs#verify-ed25519-signature) The ed25519 program is used to verify one or more ed25519 signatures. | Program | Program ID | Description | Instructions | | --- | --- | --- | --- | | Ed25519 Program | `Ed25519SigVerify111111111111111111111111111` | Verifies ed25519 signatures. If any signature fails, an error is returned. | [Instructions](https://docs.rs/solana-ed25519-program/latest/solana_ed25519_program/index.html) | The ed25519 program processes an instruction. The instruction's first `u8` contains a count of the number of signatures to be checked, followed by a single byte padding. After that, the following struct is serialized, one for each signature to be checked. Ed25519SignatureOffsets struct Ed25519SignatureOffsets { signature\_offset: u16, // offset to ed25519 signature of 64 bytes signature\_instruction\_index: u16, // instruction index to find signature public\_key\_offset: u16, // offset to public key of 32 bytes public\_key\_instruction\_index: u16, // instruction index to find public key message\_data\_offset: u16, // offset to start of message data message\_data\_size: u16, // size of message data message\_instruction\_index: u16, // index of instruction data to get message data } Signature verification pseudocode process\_instruction() { for i in 0..count { // i'th index values referenced: instructions = &transaction.message().instructions instruction\_index = ed25519\_signature\_instruction\_index != u16::MAX ? ed25519\_signature\_instruction\_index : current\_instruction; signature = instructions\[instruction\_index\].data\[ed25519\_signature\_offset..ed25519\_signature\_offset + 64\] instruction\_index = ed25519\_pubkey\_instruction\_index != u16::MAX ? ed25519\_pubkey\_instruction\_index : current\_instruction; pubkey = instructions\[instruction\_index\].data\[ed25519\_pubkey\_offset..ed25519\_pubkey\_offset + 32\] instruction\_index = ed25519\_message\_instruction\_index != u16::MAX ? ed25519\_message\_instruction\_index : current\_instruction; message = instructions\[instruction\_index\].data\[ed25519\_message\_data\_offset..ed25519\_message\_data\_offset + ed25519\_message\_data\_size\] if pubkey.verify(signature, message) != Success { return Error } } return Success } #### [Verify secp256k1 recovery](https://solana.com/docs/core/programs#verify-secp256k1-recovery) The secp256k1 program is used to verify secp256k1 public key recovery operations. | Program | Program ID | Description | Instructions | | --- | --- | --- | --- | | Secp256k1 Program | `KeccakSecp256k11111111111111111111111111111` | Verifies secp256k1 public key recovery operations (ecrecover). | [Instructions](https://docs.rs/solana-secp256k1-program/latest/solana_secp256k1_program/index.html) | The secp256k1 program processes an instruction. The instruction's first byte contains a count of the number of public keys to be checked. After that, the following struct is created once for each public key, then serialized and added to the instruction data. Secp256k1SignatureOffsets struct Secp256k1SignatureOffsets { secp\_signature\_offset: u16, // offset to \[signature,recovery\_id\] of 64+1 bytes secp\_signature\_instruction\_index: u8, // instruction index to find signature secp\_pubkey\_offset: u16, // offset to ethereum\_address pubkey of 20 bytes secp\_pubkey\_instruction\_index: u8, // instruction index to find pubkey secp\_message\_data\_offset: u16, // offset to start of message data secp\_message\_data\_size: u16, // size of message data secp\_message\_instruction\_index: u8, // instruction index to find message data } Recovery verification pseudocode process\_instruction() { for i in 0..count { // i'th index values referenced: instructions = &transaction.message().instructions signature = instructions\[secp\_signature\_instruction\_index\].data\[secp\_signature\_offset..secp\_signature\_offset + 64\] recovery\_id = instructions\[secp\_signature\_instruction\_index\].data\[secp\_signature\_offset + 64\] ref\_eth\_pubkey = instructions\[secp\_pubkey\_instruction\_index\].data\[secp\_pubkey\_offset..secp\_pubkey\_offset + 20\] message\_hash = keccak256(instructions\[secp\_message\_instruction\_index\].data\[secp\_message\_data\_offset..secp\_message\_data\_offset + secp\_message\_data\_size\]) pubkey = ecrecover(signature, recovery\_id, message\_hash) eth\_pubkey = keccak256(pubkey\[1..\])\[12..\] if eth\_pubkey != ref\_eth\_pubkey { return Error } } return Success } This allows the user to specify any instruction data in the transaction for signature and message data. By specifying a special instructions sysvar, one can also receive data from the transaction itself. Cost of the transaction will count the number of signatures to verify multiplied by the signature cost verify multiplier. The secp256r1 program is used to verify up to 8 secp256r1 signatures. | Program | Program ID | Description | Instructions | | --- | --- | --- | --- | | Secp256r1 Program | `Secp256r1SigVerify1111111111111111111111111` | Verifies up to 8 secp256r1 signatures. Takes a signature, public key, and message. Returns error if any fail. | [Instructions](https://docs.rs/solana-secp256r1-program/latest/solana_secp256r1_program/all.html) | The secp256r1 program processes an instruction. The instruction's first `u8` is a count of the number of signatures to be checked, followed by a single byte padding. After that, the following struct is created for each signature, then serialized and added to the instruction data. Secp256r1SignatureOffsets struct Secp256r1SignatureOffsets { signature\_offset: u16, // offset to compact secp256r1 signature of 64 bytes signature\_instruction\_index: u16, // instruction index to find signature public\_key\_offset: u16, // offset to compressed public key of 33 bytes public\_key\_instruction\_index: u16, // instruction index to find public key message\_data\_offset: u16, // offset to start of message data message\_data\_size: u16, // size of message data message\_instruction\_index: u16, // index of instruction data to get message data } Low S values are enforced for all signatures to avoid accidental signature malleability. Signature verification psuedocode process\_instruction() { if data.len() < SIGNATURE\_OFFSETS\_START { return Error } num\_signatures = data\[0\] as usize if num\_signatures == 0 || num\_signatures > 8 { return Error } expected\_data\_size = num\_signatures \* SIGNATURE\_OFFSETS\_SERIALIZED\_SIZE + SIGNATURE\_OFFSETS\_START if data.len() < expected\_data\_size { return Error } for i in 0..num\_signatures { offsets = parse\_signature\_offsets(data, i) signature = get\_data\_slice(data, instruction\_datas, offsets.signature\_instruction\_index, offsets.signature\_offset, SIGNATURE\_SERIALIZED\_SIZE) if s > half\_curve\_order { return Error } pubkey = get\_data\_slice(data, instruction\_datas, offsets.public\_key\_instruction\_index, offsets.public\_key\_offset, COMPRESSED\_PUBKEY\_SERIALIZED\_SIZE) message = get\_data\_slice(data, instruction\_datas, offsets.message\_instruction\_index, offsets.message\_data\_offset, offsets.message\_data\_size) if !verify\_signature(signature, pubkey, message) { return Error } } return Success } ### [Core programs](https://solana.com/docs/core/programs#core-programs) The programs in the list below provide the network's core functionality. | Program | Program ID | Description | Instructions | | --- | --- | --- | --- | | **System** | `11111111111111111111111111111111` | Create new accounts, allocate account data, assign accounts to owning programs, transfer lamports from System Program-owned accounts, and pay transaction fees | [SystemInstruction](https://docs.rs/solana-program/latest/solana_program/system_instruction/enum.SystemInstruction.html) | | **Vote** | `Vote111111111111111111111111111111111111111` | Create and manage accounts that track validator voting state and rewards | [VoteInstruction](https://docs.rs/solana-vote-program/latest/solana_vote_program/vote_instruction/enum.VoteInstruction.html) | | **Stake** | `Stake11111111111111111111111111111111111111` | Create and manage accounts representing stake and rewards for delegations to validators | [StakeInstruction](https://docs.rs/solana-sdk/latest/solana_sdk/stake/instruction/enum.StakeInstruction.html) | | **Config** | `Config1111111111111111111111111111111111111` | Add configuration data to the chain, followed by the list of public keys that are allowed to modify it. Unlike the other programs, the Config program does not define any individual instructions. It has just one implicit instruction: "store". Its instruction data is a set of keys that gate access to the account and the data stored inside of it | [ConfigInstruction](https://docs.rs/solana-config-program/latest/solana_config_program/config_instruction/index.html) | | **Compute Budget** | `ComputeBudget111111111111111111111111111111` | Set compute unit limits and prices for transactions, allowing users to control compute resources and prioritization fees | [ComputeBudgetInstruction](https://docs.rs/solana-compute-budget-interface/latest/solana_compute_budget_interface/enum.ComputeBudgetInstruction.html) | | **Address Lookup Table** | `AddressLookupTab1e1111111111111111111111111` | Manage address lookup tables, which allow transactions to reference more accounts than would otherwise fit in the transaction's account list | [ProgramInstruction](https://docs.rs/solana-sdk/latest/solana_sdk/address_lookup_table/instruction/enum.ProgramInstruction.html) | | **ZK ElGamal Proof** | `ZkE1Gama1Proof11111111111111111111111111111` | Provides zero-knowledge proof verification for ElGamal-encrypted data | — | Is this page helpful? [Previous\ \ Transaction Fees](https://solana.com/docs/core/fees) [Next\ \ Program-Derived Address](https://solana.com/docs/core/pda) ### Table of Contents [Write programs](https://solana.com/docs/core/programs#write-programs) [Update programs](https://solana.com/docs/core/programs#update-programs) [Verify programs](https://solana.com/docs/core/programs#verify-programs) [Built-in programs](https://solana.com/docs/core/programs#built-in-programs) [The System Program](https://solana.com/docs/core/programs#the-system-program) [Loader programs](https://solana.com/docs/core/programs#loader-programs) [Precompiled programs](https://solana.com/docs/core/programs#precompiled-programs) [Verify ed25519 signature](https://solana.com/docs/core/programs#verify-ed25519-signature) [Verify secp256k1 recovery](https://solana.com/docs/core/programs#verify-secp256k1-recovery) [Core programs](https://solana.com/docs/core/programs#core-programs) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/programs.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Quick Start | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) Getting Started [Quick Start](https://solana.com/docs/intro/quick-start) ========================================================= Copy MarkdownOpen Welcome to the Solana quick start guide! This hands-on guide will introduce you to the **Solana Playground** (Solpg), where you can learn core-concepts, regardless of your prior experience. In this tutorial, you will learn about: * **Solana accounts**: How the Solana network stores data * **Sending transactions**: How to interact with the Solana network by sending transactions * **Building and deploying programs**: Create your first Solana program and deploy it to the network * **Program-Derived addresses**: Learn how to create deterministic addresses for accounts * **Cross-Program Invocations**: Learn how to call other programs from within your program, enabling complex interactions and program composability [The Solana Playground](https://solana.com/docs/intro/quick-start#the-solana-playground) ----------------------------------------------------------------------------------------- The Solana Playground is a browser-based development environment that allows you to develop, deploy, and test Solana programs without installing anything locally. Follow along, copy, and paste code, and see results immediately. Basic programming knowledge helps but is not required. Time to dive in and start building with Solana! As a new user, the first step to interacting with the Solana Playground is to create a Playground [wallet](https://solana.com/docs/references/terminology#wallet) and add [SOL](https://solana.com/docs/references/terminology#sol) . This wallet will allow you to interact with the Solana network directly from your browser. [Create a Playground wallet](https://solana.com/docs/intro/quick-start#create-a-playground-wallet) --------------------------------------------------------------------------------------------------- ### [Navigate to the Solana Playground](https://solana.com/docs/intro/quick-start#navigate-to-the-solana-playground) Using your web browser, navigate to the [Solana Playground](https://beta.solpg.io/) . ### [Connect to the Playground](https://solana.com/docs/intro/quick-start#connect-to-the-playground) Click the 🔴 **Not connected** text at the bottom left corner of the screen. Not Connected ### [Save your keypair](https://solana.com/docs/intro/quick-start#save-your-keypair) Click **Save keypair** to save your key pair locally. When you're ready, click **Continue**. Create Playground Wallet At the bottom of the screen, you will see that you are now connected to the Playground wallet. You will also see the [connected cluster](https://solana.com/docs/references/terminology#connected-cluster) (`devnet`), the [wallet address](https://solana.com/docs/references/terminology#wallet-address) , and your [SOL](https://solana.com/docs/references/terminology#sol) balance. Connected Your browser's local storage saves your Playground wallet. Clearing your browser cache will remove your saved wallet. Use your Playground wallet for testing and development only. Never send real assets (from [`mainnet`](https://solana.com/docs/references/terminology#connected-cluster) ) to this address. Congratulations! You created your first Solana Wallet. You are now ready to add SOL to your wallet. ### [Add SOL to your wallet](https://solana.com/docs/intro/quick-start#add-sol-to-your-wallet) Before starting development, you need to add devnet SOL to your wallet. As a developer, SOL is used for two main use cases: * To create new accounts for storing data or deploying programs * Paying transaction fees when interacting with the Solana network You can add devnet SOL to your wallet using the Playground terminal or with the Devnet Faucet. Each option is described below: #### [Option 1: Use the Playground terminal](https://solana.com/docs/intro/quick-start#option-1-use-the-playground-terminal) Run the following command in the Playground terminal: Terminal $ solana airdrop 5 Copy #### [Option 2: Use the Devnet faucet](https://solana.com/docs/intro/quick-start#option-2-use-the-devnet-faucet) If option 1 fails, due to rate limits or other errors, use Solana's [Web Faucet](https://faucet.solana.com/) . * Enter your wallet address * Select an amount * Click **Confirm Airdrop** Faucet Airdrop Is this page helpful? [Previous\ \ Surfpool CLI Basics](https://solana.com/docs/intro/installation/surfpool-cli-basics) [Next\ \ Reading from Network](https://solana.com/docs/intro/quick-start/reading-from-network) ### Table of Contents [The Solana Playground](https://solana.com/docs/intro/quick-start#the-solana-playground) [Create a Playground wallet](https://solana.com/docs/intro/quick-start#create-a-playground-wallet) [Navigate to the Solana Playground](https://solana.com/docs/intro/quick-start#navigate-to-the-solana-playground) [Connect to the Playground](https://solana.com/docs/intro/quick-start#connect-to-the-playground) [Save your keypair](https://solana.com/docs/intro/quick-start#save-your-keypair) [Add SOL to your wallet](https://solana.com/docs/intro/quick-start#add-sol-to-your-wallet) [Option 1: Use the Playground terminal](https://solana.com/docs/intro/quick-start#option-1-use-the-playground-terminal) [Option 2: Use the Devnet faucet](https://solana.com/docs/intro/quick-start#option-2-use-the-devnet-faucet) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/quick-start/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Quick Start | Solana --- # Payments | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Payments](https://solana.com/docs) [Payments](https://solana.com/docs/payments) ============================================= Copy MarkdownOpen Solana is built with certain features that are ideal for payments including native fee abstraction, sub-cent fees, embedded memos, predictably stable fees, and fast confirmation times. In 2025, Solana processed over [**$1 trillion**](https://app.artemisanalytics.com/asset/solana?from=assets) in stablecoin volume. This guide will help you build advanced payment systems for multiple use cases including remittances, treasury optimization, global payouts, cross-border payments, merchant acceptance, invoices, and more. [Get Started](https://solana.com/docs/payments#get-started) ------------------------------------------------------------ [### How Payments Work on Solana\ \ New to Solana? Learn the core concepts of sending and receiving payments on Solana.](https://solana.com/docs/payments/how-payments-work) [### Send a Payment\ \ Send your first stablecoin payment between accounts with optional memos for reconciliation.](https://solana.com/docs/payments/send-payments) [### Accept Payments\ \ Integrate stablecoin payments into your checkout flow.](https://solana.com/docs/payments/accept-payments) [### Payouts & Disbursements\ \ Disburse funds to users, vendors, or employees at scale.](https://solana.com/docs/payments/send-payments/payment-processing) [Why Solana](https://solana.com/docs/payments#why-solana) ---------------------------------------------------------- * **Instant settlement**. Funds secured in ~400ms. No T+2, no manual batch processing, no reconciliation delays. * **Sub-cent fees**. Median fee ~$0.001 per transaction. Batch multiple payments into a single transaction to improve payment efficiency and reduce costs further. * **Local fee markets.** Dedicated fee markets for payments so your flows are unaffected by other network activity. * **Parallel execution**. Process transactions in parallel to further increase your payment throughput. * **Familiar UX**. Sponsor or abstract away network fees so users pay in stablecoins without acquiring SOL. * **Programmable**. Build custom payment applications with compliance built in (reconciliation memos, blacklists, automated tax accounting, etc.). Is this page helpful? [Previous\ \ getStakeActivation](https://solana.com/docs/rpc/deprecated/getstakeactivation) [Next\ \ How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) ### Table of Contents [Get Started](https://solana.com/docs/payments#get-started) [Why Solana](https://solana.com/docs/payments#why-solana) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Solana RPC Methods: HTTP & Websockets | Solana This website uses cookies to offer you a better browsing experience. Find out more on how we use cookies. Opt-out[Details](https://solana.com/privacy-policy#collection-of-information) Accept [Solana Documentation](https://solana.com/docs) [Solana RPC Methods & Documentation](https://solana.com/docs/rpc) ================================================================== Copy MarkdownOpen Interact with Solana nodes directly with the JSON RPC API via the HTTP and Websocket methods. [Configuring State Commitment](https://solana.com/docs/rpc#configuring-state-commitment) ----------------------------------------------------------------------------------------- For preflight checks and transaction processing, Solana nodes choose which bank state to query based on a commitment requirement set by the client. The commitment describes how finalized a block is at that point in time. When querying the ledger state, it's recommended to use lower levels of commitment to report progress and higher levels to ensure the state will not be rolled back. In descending order of commitment (most finalized to least finalized), clients may specify: * `finalized` - the node will query the most recent block confirmed by supermajority of the cluster as having reached maximum lockout, meaning the cluster has recognized this block as finalized * `confirmed` - the node will query the most recent block that has been voted on by supermajority of the cluster. * It incorporates votes from gossip and replay. * It does not count votes on descendants of a block, only direct votes on that block. * This confirmation level also upholds "optimistic confirmation" guarantees in release 1.3 and onwards. * `processed` - the node will query its most recent block. Note that the block may still be skipped by the cluster. For processing many dependent transactions in series, it's recommended to use `confirmed` commitment, which balances speed with rollback safety. For total safety, it's recommended to use `finalized` commitment. ### [Default Commitment](https://solana.com/docs/rpc#default-commitment) If commitment configuration is not provided, the node will [default to `finalized` commitment](https://github.com/anza-xyz/agave/blob/aa0922d6845e119ba466f88497e8209d1c82febc/sdk/src/commitment_config.rs#L199-L203) Only methods that query bank state accept the commitment parameter. They are indicated in the API Reference below. [RpcResponse Structure](https://solana.com/docs/rpc#rpcresponse-structure) --------------------------------------------------------------------------- Many methods that take a commitment parameter return an RpcResponse JSON object comprised of two parts: * `context` : An RpcResponseContext JSON structure including a `slot` field at which the operation was evaluated. * `value` : The value returned by the operation itself. [Parsed Responses](https://solana.com/docs/rpc#parsed-responses) ----------------------------------------------------------------- Some methods support an `encoding` parameter, and can return account or instruction data in parsed JSON format if `"encoding":"jsonParsed"` is requested and the node has a parser for the owning program. Solana nodes currently support JSON parsing for the following native and SPL programs: | Program | Account State | Instructions | | --- | --- | --- | | Address Lookup | v1.15.0 | v1.15.0 | | BPF Loader | n/a | stable | | BPF Upgradeable Loader | stable | stable | | Config | stable | | | SPL Associated Token Account | n/a | stable | | SPL Memo | n/a | stable | | SPL Token | stable | stable | | SPL Token 2022 | stable | stable | | Stake | stable | stable | | Vote | stable | stable | The list of account parsers can be found [here](https://github.com/solana-labs/solana/blob/master/account-decoder/src/parse_account_data.rs) , and instruction parsers [here](https://github.com/solana-labs/solana/blob/master/transaction-status/src/parse_instruction.rs) . [Filter criteria](https://solana.com/docs/rpc#filter-criteria) --------------------------------------------------------------- Some methods support providing a `filters` object to enable pre-filtering the data returned within the RpcResponse JSON object. The following filters exist: * `memcmp: object` - compares a provided series of bytes with program account data at a particular offset. Fields: * `offset: usize` - offset into program account data to start comparison * `bytes: string` - data to match, as encoded string * `encoding: string` - encoding for filter `bytes` data, either "base58" or "base64". Data is limited in size to 128 or fewer decoded bytes. **NEW: This field, and base64 support generally, is only available in solana-core v1.14.0 or newer. Please omit when querying nodes on earlier versions** * `dataSize: u64` - compares the program account data length with the provided data size Is this page helpful? [Previous\ \ Terminology](https://solana.com/docs/references/terminology) [Next\ \ Data Structures as JSON](https://solana.com/docs/rpc/json-structures) ### Table of Contents [Configuring State Commitment](https://solana.com/docs/rpc#configuring-state-commitment) [Default Commitment](https://solana.com/docs/rpc#default-commitment) [RpcResponse Structure](https://solana.com/docs/rpc#rpcresponse-structure) [Parsed Responses](https://solana.com/docs/rpc#parsed-responses) [Filter criteria](https://solana.com/docs/rpc#filter-criteria) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/rpc/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Solana RPC Methods: HTTP & Websockets | Solana --- # Clusters and Public RPC Endpoints | Solana [Solana Documentation](https://solana.com/docs) References [Clusters and Public RPC Endpoints](https://solana.com/docs/references/clusters) ================================================================================= Copy MarkdownOpen The Solana blockchain has several different groups of validators, known as Clusters. Each serving different purposes within the overall ecosystem and containing dedicated API nodes to fulfill [JSON-RPC](https://solana.com/docs/rpc/) requests for their respective Cluster. The individual nodes within a Cluster are owned and operated by third parties, with a public endpoint available for each. [Solana public RPC endpoints](https://solana.com/docs/references/clusters#solana-public-rpc-endpoints) ------------------------------------------------------------------------------------------------------- The Solana Labs organization operates a public RPC endpoint for each Cluster. Each of these public endpoints are subject to rate limits, but are available for users and developers to interact with the Solana blockchain. > Public endpoint rate limits are subject to change. The specific rate limits listed on this document are not guaranteed to be the most up-to-date. ### [Using explorers with different Clusters](https://solana.com/docs/references/clusters#using-explorers-with-different-clusters) Many of the popular Solana blockchain explorers support selecting any of the Clusters, often allowing advanced users to add a custom/private RPC endpoint as well. An example of some of these Solana blockchain explorers include: * [http://explorer.solana.com/](https://explorer.solana.com/) . * [http://orb.helius.dev/](https://orb.helius.dev/) . * [http://solana.fm/](https://solana.fm/) . * [http://solscan.io/](https://solscan.io/) . * [http://solanabeach.io/](http://solanabeach.io/) . * [http://validators.app/](http://validators.app/) . [On a high level](https://solana.com/docs/references/clusters#on-a-high-level) ------------------------------------------------------------------------------- * Mainnet: Live production environment for deployed applications. * Devnet: Testing with public accessibility for developers experimenting with their applications. * Testnet: Stress-testing for network upgrades and validator performance. **Example use cases**: You may want to debug a new program on Devnet or verify performance metrics on Testnet before Mainnet deployment. | **Cluster** | **Endpoint** | **Purpose** | **Notes** | | --- | --- | --- | --- | | Mainnet | `https://api.mainnet.solana.com` | Live production environment | Requires SOL for transactions | | Devnet | `https://api.devnet.solana.com` | Public testing and development | Free SOL airdrop for testing | | Testnet | `https://api.testnet.solana.com` | Validator and stress testing | May have intermittent downtime | [Devnet](https://solana.com/docs/references/clusters#devnet) ------------------------------------------------------------- Devnet serves as a playground for anyone who wants to take Solana for a test drive, as a user, token holder, app developer, or validator. * Application developers should target Devnet. * Potential validators should first target Devnet. * Key differences between Devnet and Mainnet: * Devnet tokens are **not real** * Devnet includes a token faucet for airdrops for application testing * Devnet may be subject to ledger resets * Devnet typically runs the same software release branch version as Mainnet Beta, but may run a newer minor release version than Mainnet. * Gossip entrypoint for Devnet: `entrypoint.devnet.solana.com:8001` ### [Devnet endpoint](https://solana.com/docs/references/clusters#devnet-endpoint) * `https://api.devnet.solana.com` - single Solana Labs hosted API node; rate-limited #### [Example `solana` command-line configuration](https://solana.com/docs/references/clusters#example-solana-command-line-configuration) To connect to the `devnet` Cluster using the Solana CLI: solana config set \--url https://api.devnet.solana.com ### [Devnet rate limits](https://solana.com/docs/references/clusters#devnet-rate-limits) * Maximum number of requests per 10 seconds per IP: 100 * Maximum number of requests per 10 seconds per IP for a single RPC: 40 * Maximum concurrent connections per IP: 40 * Maximum connection rate per 10 seconds per IP: 40 * Maximum amount of data per 30 second: 100 MB [Testnet](https://solana.com/docs/references/clusters#testnet) --------------------------------------------------------------- Testnet is where the Solana core contributors stress test recent release features on a live cluster, particularly focused on network performance, stability and validator behavior. * Testnet tokens are **not real** * Testnet may be subject to ledger resets. * Testnet includes a token faucet for airdrops for application testing * Testnet typically runs a newer software release branch than both Devnet and Mainnet * Gossip entrypoint for Testnet: `entrypoint.testnet.solana.com:8001` ### [Testnet endpoint](https://solana.com/docs/references/clusters#testnet-endpoint) * `https://api.testnet.solana.com` - single Solana Labs API node; rate-limited #### [Example `solana` command-line configuration](https://solana.com/docs/references/clusters#example-solana-command-line-configuration-1) To connect to the `testnet` Cluster using the Solana CLI: solana config set \--url https://api.testnet.solana.com ### [Testnet rate limits](https://solana.com/docs/references/clusters#testnet-rate-limits) * Maximum number of requests per 10 seconds per IP: 100 * Maximum number of requests per 10 seconds per IP for a single RPC: 40 * Maximum concurrent connections per IP: 40 * Maximum connection rate per 10 seconds per IP: 40 * Maximum amount of data per 30 second: 100 MB [Mainnet](https://solana.com/docs/references/clusters#mainnet) --------------------------------------------------------------- A permissionless, persistent cluster for Solana users, builders, validators and token holders. * Tokens that are issued on Mainnet are **real** SOL * Gossip entrypoint for Mainnet: `entrypoint.mainnet.solana.com:8001` ### [Mainnet endpoint](https://solana.com/docs/references/clusters#mainnet-endpoint) * `https://api.mainnet.solana.com` - Solana Labs hosted API node cluster, backed by a load balancer; rate-limited #### [Example `solana` command-line configuration](https://solana.com/docs/references/clusters#example-solana-command-line-configuration-2) To connect to the `mainnet` Cluster using the Solana CLI: solana config set \--url https://api.mainnet.solana.com ### [Mainnet rate limits](https://solana.com/docs/references/clusters#mainnet-rate-limits) * Maximum number of requests per 10 seconds per IP: 100 * Maximum number of requests per 10 seconds per IP for a single RPC: 40 * Maximum concurrent connections per IP: 40 * Maximum connection rate per 10 seconds per IP: 40 * Maximum amount of data per 30 seconds: 100 MB > The public RPC endpoints are not intended for production applications. Please use dedicated/private RPC servers when you launch your application, drop NFTs, etc. The public services are subject to abuse and rate limits may change without prior notice. Likewise, high-traffic websites may be blocked without prior notice. [Common HTTP Error Codes](https://solana.com/docs/references/clusters#common-http-error-codes) ----------------------------------------------------------------------------------------------- * 403 -- Your IP address or website has been blocked. It is time to run your own RPC server(s) or find a private service. * 429 -- Your IP address is exceeding the rate limits. Slow down! Use the [Retry-After](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) HTTP response header to determine how long to wait before making another request. Is this page helpful? [Previous\ \ Solana Gaming SDKs](https://solana.com/docs/clients/community/game-sdks) [Next\ \ Staking](https://solana.com/docs/references/staking) ### Table of Contents [Solana public RPC endpoints](https://solana.com/docs/references/clusters#solana-public-rpc-endpoints) [Using explorers with different Clusters](https://solana.com/docs/references/clusters#using-explorers-with-different-clusters) [On a high level](https://solana.com/docs/references/clusters#on-a-high-level) [Devnet](https://solana.com/docs/references/clusters#devnet) [Devnet endpoint](https://solana.com/docs/references/clusters#devnet-endpoint) [Example `solana` command-line configuration](https://solana.com/docs/references/clusters#example-solana-command-line-configuration) [Devnet rate limits](https://solana.com/docs/references/clusters#devnet-rate-limits) [Testnet](https://solana.com/docs/references/clusters#testnet) [Testnet endpoint](https://solana.com/docs/references/clusters#testnet-endpoint) [Example `solana` command-line configuration](https://solana.com/docs/references/clusters#example-solana-command-line-configuration-1) [Testnet rate limits](https://solana.com/docs/references/clusters#testnet-rate-limits) [Mainnet](https://solana.com/docs/references/clusters#mainnet) [Mainnet endpoint](https://solana.com/docs/references/clusters#mainnet-endpoint) [Example `solana` command-line configuration](https://solana.com/docs/references/clusters#example-solana-command-line-configuration-2) [Mainnet rate limits](https://solana.com/docs/references/clusters#mainnet-rate-limits) [Common HTTP Error Codes](https://solana.com/docs/references/clusters#common-http-error-codes) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/references/clusters.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Tokens on Solana | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) =================================================== Copy MarkdownOpen Tokens are digital assets that represent ownership over diverse categories of assets. Tokenization enables the digitalization of property rights. Tokens on Solana are referred to as SPL ([Solana Program Library](https://github.com/solana-program) ) Tokens. This section covers the basic concepts of how tokens are represented on Solana. Refer to the [SPL Token Basics](https://solana.com/docs/tokens/basics) section for code examples. [Key Points](https://solana.com/docs/core/tokens#key-points) ------------------------------------------------------------- * [Token Programs](https://solana.com/docs/core/tokens#token-program) contain all instruction logic for interacting with tokens on the network (both fungible and non-fungible). * A [Mint Account](https://solana.com/docs/core/tokens#mint-account) represents a specific token and stores global metadata about the token such as the total supply and mint authority (address authorized to create new units of a token). * A [Token Account](https://solana.com/docs/core/tokens#token-account) tracks individual ownership of tokens for a specific mint account for a specific owner. * An [Associated Token Account](https://solana.com/docs/core/tokens#associated-token-account) is a Token Account created with an address derived from the owner and mint account addresses. [Token Programs](https://solana.com/docs/core/tokens#token-programs) --------------------------------------------------------------------- The Solana ecosystem has two main Token Programs. Source code for both programs below. [### Token Program (Original)\ \ * Basic token capability (mint, transfer, etc.)\ * Immutable and widely used](https://github.com/solana-program/token) [### Token Extension Program (Token 2022)\ \ * Includes all original Token Program features\ * Adds features through "extensions"](https://github.com/solana-program/token-2022) Token Programs contains all instruction logic for interacting with tokens on the network (both fungible and non-fungible). All tokens on Solana are effectively [data accounts](https://solana.com/docs/core/accounts#data-account) owned by a Token Program. Token Program ### [Mint Account](https://solana.com/docs/core/tokens#mint-account) Tokens on Solana are uniquely identified by the address of a [Mint Account](https://github.com/solana-program/token/blob/6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a/program/src/state.rs#L16-L30) owned by the Token Program. This account acts as a global counter for a specific token and stores data such as: * **Supply**: Total supply of the token * **Decimals**: Decimal precision of the token * **Mint authority**: The account authorized to create new units of the token, increasing the supply * **Freeze authority**: The account authorized to freeze tokens in a Token Account, preventing them from being transferred or burned Mint Account The full details stored on each Mint Account include the following: Mint Account State pub struct Mint { /// Optional authority used to mint new tokens. The mint authority may only /// be provided during mint creation. If no mint authority is present /// then the mint has a fixed supply and no further tokens may be /// minted. pub mint\_authority: COption, /// Total supply of tokens. pub supply: u64, /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, /// Is \`true\` if this structure has been initialized pub is\_initialized: bool, /// Optional authority to freeze token accounts. pub freeze\_authority: COption, } For reference, here is a Solana Explorer link to the [USDC Mint Account](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) . ### [Token Account](https://solana.com/docs/core/tokens#token-account) The Token Program creates [Token Accounts](https://github.com/solana-program/token/blob/6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a/program/src/state.rs#L87-L108) to track individual ownership of each token unit. A Token Account stores data such as: * **Mint**: The token the Token Account holds units of * **Owner**: The account authorized to transfer tokens from the Token Account * **Amount**: Number of the tokens the Token Account currently holds Token Account The full details stored on each Token Account include the following: Token Account State pub struct Account { /// The mint associated with this account pub mint: Pubkey, /// The owner of this account. pub owner: Pubkey, /// The amount of tokens this account holds. pub amount: u64, /// If \`delegate\` is \`Some\` then \`delegated\_amount\` represents /// the amount authorized by the delegate pub delegate: COption, /// The account's state pub state: AccountState, /// If is\_native.is\_some, this is a native token, and the value logs the /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. pub is\_native: COption, /// The amount delegated pub delegated\_amount: u64, /// Optional authority to close the account. pub close\_authority: COption, } A wallet needs a token account for each token (mint) it wants to hold, with the wallet address set as the token account owner. Each wallet can own multiple token accounts for the same token (mint), but a token account can only have one owner and hold units of one token (mint). Account Relationship Note that each Token Account's data includes an `owner` field identifying who has authority over the Token Account. This differs from the program owner specified in the base [Account](https://solana.com/docs/core/accounts#account-type) type, which is the Token Program for all Token Accounts. ### [Associated Token Account](https://solana.com/docs/core/tokens#associated-token-account) Associated Token Accounts simplify the process of finding a token account's address for a specific mint and owner. Think of the Associated Token Account as the "default" token account for a specific mint and owner. An Associated Token Account is created with an address derived from the owner's address and the mint account's address. It's important to understand that an Associated Token Account is just a token account with a specific address. This introduces a key concept in Solana development: [Program Derived Address (PDA)](https://solana.com/docs/core/pda) . A PDA derives an address deterministically using predefined inputs, making it easy to find the address of an account. Associated Token Account Note that each wallet needs its own token account to hold tokens from the same mint. Accounts Relationship Expanded [Token CLI Examples](https://solana.com/docs/core/tokens#token-cli-examples) ----------------------------------------------------------------------------- The `spl-token` CLI helps you experiment with SPL tokens. The examples below use the [Solana Playground](https://beta.solpg.io/) terminal to run CLI commands directly in the browser without local installation. Creating tokens and accounts requires SOL for account rent deposits and transaction fees. For first-time Solana Playground users, create a Playground wallet and run the `solana airdrop` command in the Playground terminal. You can also get devnet SOL from the public [web faucet](https://faucet.solana.com/) . Terminal $ solana airdrop 2 Copy Run `spl-token --help` to see all available commands. Terminal $ spl-token --help Copy To install the `spl-token` CLI locally, run: Terminal $ cargo install spl-token-cli Copy Find more examples in the `spl-token` [documentation](https://www.solana-program.com/docs/token) . The account addresses shown in your terminal output differ from the examples below. Use the addresses from your Playground terminal when following along. For example, the `create-token` command outputs a mint account address with your Playground wallet as the mint authority. ### [Create a New Token](https://solana.com/docs/core/tokens#create-a-new-token) To create a new token (mint account), run: Terminal $ spl-token create-token Copy The output looks like: Terminal Output Creating token 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Address: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Decimals: 9 Signature: 44fvKfT1ezBUwdzrCys3fvCdFxbLMnNvBstds76QZyE6cXag5NupBprSXwxPTzzjrC3cA6nvUZaLFTvmcKyzxrm1 A new mint account starts with zero supply. Check the current supply with: Terminal $ spl-token supply Copy The `supply` command for a new token returns `0`: Example spl-token supply 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Creating a new Mint Account requires a transaction with two instructions. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ce32ecffcf4b13384d00f) . 1. The System Program creates a new account with space for the Mint Account data and transfers ownership to the Token Program. 2. The Token Program initializes the data of the new account as a Mint Account ### [Create Token Account](https://solana.com/docs/core/tokens#create-token-account) To hold tokens of a specific mint, create a token account: Terminal $ spl-token create-account Copy Example command: Example spl-token create-account 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Output: Terminal Output Creating account AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 Signature: 2BtrynuCLX9CNofFiaw6Yzbx6hit66pup9Sk7aFjwU2NEbFz7NCHD9w9sWhrCfEd73XveAGK1DxFpJoQZPXU9tS1 The `create-account` command creates an associated token account with your wallet address as the owner. To create a token account with a different owner: Terminal $ spl-token create-account --owner Copy Note: `` specifies the mint account for the token account. Example command: Example spl-token create-account \--owner 2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Output: Terminal Output Creating account Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Signature: 44vqKdfzspT592REDPY4goaRJH3uJ3Ce13G4BCuUHg35dVUbHuGTHvqn4ZjYF9BGe9QrjMfe9GmuLkQhSZCBQuEt Creating an Associated Token Account requires one instruction that invokes the [Associated Token Program](https://github.com/solana-program/associated-token-account) . Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ce868cffcf4b13384d011) . The Associated Token Program uses [Cross Program Invocations](https://solana.com/docs/core/cpi) to: * [Invoke the System Program](https://github.com/solana-program/associated-token-account/blob/9d94201e8158f06015ff80ad47fefac62a2ec450/program/src/tools/account.rs#L19) to create a new account using the provided PDA as the address * [Invoke the Token Program](https://github.com/solana-program/associated-token-account/blob/9d94201e8158f06015ff80ad47fefac62a2ec450/program/src/processor.rs#L138-L161) to initialize the Token Account data To create a new Token Account with a new keypair instead of an Associated Token Account address, send a transaction with two instructions. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ce716cffcf4b13384d010) . 1. The System Program creates a new account with space for the Token Account data and transfers ownership to the Token Program. 2. The Token Program initializes the data as a Token Account ### [Mint Tokens](https://solana.com/docs/core/tokens#mint-tokens) To create new units of a token, mint tokens to a Token Account: Terminal $ spl-token mint \[OPTIONS\] \[--\] \[RECIPIENT\_TOKEN\_ACCOUNT\_ADDRESS\] Copy Example command: Example spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 Output: Terminal Output Minting 100 tokens Token: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Recipient: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 Signature: 2NJ1m7qCraPSBAVxbr2ssmWZmBU9Jc8pDtJAnyZsZJRcaYCYMqq1oRY1gqA4ddQno3g3xcnny5fzr1dvsnFKMEqG To mint tokens to a different token account: Example spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 -- Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Output: Terminal Output Minting 100 tokens Token: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Signature: 3SQvNM3o9DsTiLwcEkSPT1Edr14RgE2wC54TEjonEP2swyVCp2jPWYWdD6RwXUGpvDNUkKWzVBZVFShn5yntxVd7 The `MintTo` instruction on the Token Program creates new tokens. The mint authority must sign the transaction. The instruction mints tokens to a Token Account and increases the total supply on the Mint Account. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660cea45cffcf4b13384d012) . ### [Transfer Tokens](https://solana.com/docs/core/tokens#transfer-tokens) To transfer tokens between token accounts: Terminal spl-token transfer \[OPTIONS\] Example command: Example spl-token transfer 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Output: Terminal Output Transfer 100 tokens Sender: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9 Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt Signature: 5y6HVwV8V2hHGLTVmTmdySRiEUCZnWmkasAvJ7J6m7JR46obbGKCBqUFgLpZu5zQGwM4Xy6GZ4M5LKd1h6Padx3o The `Transfer` instruction on the Token Program handles token transfers. The owner of the sender's Token Account must sign the transaction. The instruction moves tokens between Token Accounts. Here's a Javascript example on [Solana Playground](https://beta.solpg.io/660ced84cffcf4b13384d013) . Both sender and recipient need token accounts for the specific token (mint). The sender can include instructions to create the recipient's token account in the same transaction. ### [Create Token Metadata](https://solana.com/docs/core/tokens#create-token-metadata) The Token Extensions Program lets you store metadata (name, symbol, image link) directly on the Mint Account. To create a token with metadata extension: Example spl-token create-token \--program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb \--enable-metadata Output: Terminal Output Creating token BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb To initialize metadata inside the mint, please run \`spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP \`, and sign with the mint authority. Address: BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP Decimals: 9 Signature: 5iQofFeXdYhMi9uTzZghcq8stAaa6CY6saUwcdnELST13eNSifiuLbvR5DnRt311frkCTUh5oecj8YEvZSB3wfai To initialize the metadata: Terminal spl-token initialize-metadata The token URI links to off-chain metadata. See an example JSON format [here](https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json) . Example command: Example spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP "TokenName" "TokenSymbol" "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json" View the metadata on [Solana Explorer](https://explorer.solana.com/address/BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP?cluster=devnet) . Learn more in the [Metadata Extension Guide](https://solana.com/developers/guides/token-extensions/metadata-pointer) . For details about Token Extensions, see the Token Extensions [Getting Started Guide](https://solana.com/developers/guides/token-extensions/getting-started) and the [SPL documentation](https://www.solana-program.com/docs/token-2022/extensions) . Is this page helpful? [Previous\ \ Cross Program Invocation](https://solana.com/docs/core/cpi) [Next\ \ SPL Token Basics](https://solana.com/docs/tokens/basics) ### Table of Contents [Key Points](https://solana.com/docs/core/tokens#key-points) [Token Programs](https://solana.com/docs/core/tokens#token-programs) [Mint Account](https://solana.com/docs/core/tokens#mint-account) [Token Account](https://solana.com/docs/core/tokens#token-account) [Associated Token Account](https://solana.com/docs/core/tokens#associated-token-account) [Token CLI Examples](https://solana.com/docs/core/tokens#token-cli-examples) [Create a New Token](https://solana.com/docs/core/tokens#create-a-new-token) [Create Token Account](https://solana.com/docs/core/tokens#create-token-account) [Mint Tokens](https://solana.com/docs/core/tokens#mint-tokens) [Transfer Tokens](https://solana.com/docs/core/tokens#transfer-tokens) [Create Token Metadata](https://solana.com/docs/core/tokens#create-token-metadata) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Tokens on Solana | Solana --- # Instructions | Solana [Solana Documentation](https://solana.com/docs) [Core Concepts](https://solana.com/docs/core) [Instructions](https://solana.com/docs/core/instructions) ========================================================== Copy MarkdownOpen Instructions are the fundamental building block for interacting with the Solana blockchain. An instruction is essentially a public function that anyone using the Solana network can call. Each instruction is used to perform a specific action. The execution logic for instructions are stored on [programs](https://solana.com/docs/core/programs) , where each program defines its own set of instructions. To interact with the Solana network, one or more instructions are added to a [transaction](https://solana.com/docs/core/transactions) and sent to the network to be processed. [SOL transfer example](https://solana.com/docs/core/instructions#sol-transfer-example) --------------------------------------------------------------------------------------- The diagram below shows how transactions and instructions work together to allow users to interact with the network. In this example, SOL is transferred from one account to another. The sender account's [metadata](https://solana.com/docs/core/instructions#account-metadata) indicates that it must sign for the transaction. (This allows the System Program to deduct [lamports](https://solana.com/docs/references/terminology#lamport) .) Both the sender and recipient accounts must be writable, in order for their lamport balance to change. To execute this instruction, the sender's wallet sends the transaction containing its [signature](https://solana.com/docs/references/terminology#signature) and the message containing the SOL transfer instruction. SOL transfer diagram After the transaction is sent, the System Program processes the transfer instruction and updates the lamport balance of both accounts. SOL transfer process diagram The example below shows the code relevant to the above diagrams. (See the System Program's transfer [instruction](https://github.com/anza-xyz/agave/blob/v2.1.13/programs/system/src/system_processor.rs#L183) .) Kit Legacy Rust import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; // Create a connection to cluster const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate sender and recipient keypairs const sender \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); const LAMPORTS\_PER\_SOL \= 1\_000\_000\_000n; const transferAmount \= lamports(LAMPORTS\_PER\_SOL / 100n); // 0.01 SOL // Fund sender with airdrop await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: sender.address, lamports: lamports(LAMPORTS\_PER\_SOL), // 1 SOL commitment: "confirmed" }); // Check balance before transfer const { value: preBalance1 } \= await rpc.getBalance(sender.address).send(); const { value: preBalance2 } \= await rpc.getBalance(recipient.address).send(); // Create a transfer instruction for transferring SOL from sender to recipient const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount // 0.01 SOL in lamports }); // Add the transfer instruction to a new transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(sender, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[transferInstruction\], tx) ); // Send the transaction to the network const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); const transactionSignature \= getSignatureFromTransaction(signedTransaction); // Check balance after transfer const { value: postBalance1 } \= await rpc.getBalance(sender.address).send(); const { value: postBalance2 } \= await rpc.getBalance(recipient.address).send(); console.log( "Sender prebalance:", Number(preBalance1) / Number(LAMPORTS\_PER\_SOL) ); console.log( "Recipient prebalance:", Number(preBalance2) / Number(LAMPORTS\_PER\_SOL) ); console.log( "Sender postbalance:", Number(postBalance1) / Number(LAMPORTS\_PER\_SOL) ); console.log( "Recipient postbalance:", Number(postBalance2) / Number(LAMPORTS\_PER\_SOL) ); console.log("Transaction Signature:", transactionSignature); Console RunClick to execute the code. Kit Legacy Rust import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; // Create a connection to cluster const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate sender and recipient keypairs const sender \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); const LAMPORTS\_PER\_SOL \= 1\_000\_000\_000n; const transferAmount \= lamports(LAMPORTS\_PER\_SOL / 100n); // 0.01 SOL // Fund sender with airdrop await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: sender.address, lamports: lamports(LAMPORTS\_PER\_SOL), // 1 SOL commitment: "confirmed" }); // Check balance before transfer const { value: preBalance1 } \= await rpc.getBalance(sender.address).send(); const { value: preBalance2 } \= await rpc.getBalance(recipient.address).send(); // Create a transfer instruction for transferring SOL from sender to recipient const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount // 0.01 SOL in lamports }); // Add the transfer instruction to a new transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(sender, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[transferInstruction\], tx) ); // Send the transaction to the network const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); const transactionSignature \= getSignatureFromTransaction(signedTransaction); // Check balance after transfer const { value: postBalance1 } \= await rpc.getBalance(sender.address).send(); const { value: postBalance2 } \= await rpc.getBalance(recipient.address).send(); console.log( "Sender prebalance:", Number(preBalance1) / Number(LAMPORTS\_PER\_SOL) ); console.log( "Recipient prebalance:", Number(preBalance2) / Number(LAMPORTS\_PER\_SOL) ); console.log( "Sender postbalance:", Number(postBalance1) / Number(LAMPORTS\_PER\_SOL) ); console.log( "Recipient postbalance:", Number(postBalance2) / Number(LAMPORTS\_PER\_SOL) ); console.log("Transaction Signature:", transactionSignature); Console RunClick to execute the code. [Instructions](https://solana.com/docs/core/instructions#instructions) ----------------------------------------------------------------------- Diagram depicting a transaction with an instruction, broken up into its 3 components An [`Instruction`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/instruction/src/lib.rs#L94) consists of the following information: * `program_id`: The [ID](https://solana.com/docs/core/instructions#program-id) of the program being invoked. * `accounts`: An array of [account metadata](https://solana.com/docs/core/instructions#account-metadata) * `data`: A byte array with additional \[data\] to be used by the instruction. Instruction struct pub struct Instruction { /// Pubkey of the program that executes this instruction. pub program\_id: Pubkey, /// Metadata describing accounts that should be passed to the program. pub accounts: Vec, /// Opaque data passed to the program for its own interpretation. pub data: Vec, } ### [Program ID](https://solana.com/docs/core/instructions#program-id) The instruction's [`program_id`](https://solana.com/docs/references/terminology#program-id) is the public key address of the program that contains the instruction's business logic. ### [Account metadata](https://solana.com/docs/core/instructions#account-metadata) The instruction's `accounts` array is an array of [`AccountMeta`](https://github.com/anza-xyz/agave/blob/v2.1.13/sdk/instruction/src/account_meta.rs#L25) structs. Metadata must be provided for each account the instruction interacts with. (This allows transaction to execute instructions in parallel, as long as they do not modify the same account.) The diagram below depicts a transaction that contains a single instruction. The instruction's `accounts` array contains metadata for two accounts. A transaction with one instruction. The instruction contains two AccountMeta structs in its accounts array. The account metadata includes the following information: * pubkey: The account's public key address * is\_signer: Set to `true` if the account must sign the transaction * is\_writable: Set to `true` if the instruction modifies the account's data To know which accounts an instruction requires, including which must be writable, read-only, or sign the transaction, you must refer to the implementation of the instruction, as defined by the program. AccountMeta pub struct AccountMeta { /// An account's public key. pub pubkey: Pubkey, /// True if an \`Instruction\` requires a \`Transaction\` signature matching \`pubkey\`. pub is\_signer: bool, /// True if the account data or metadata may be mutated during program execution. pub is\_writable: bool, } ### [Data](https://solana.com/docs/core/instructions#data) The instruction's `data` is a byte array that specifies which of the program's instruction to invoke. It also includes any arguments required by the instruction. [Create instruction example](https://solana.com/docs/core/instructions#create-instruction-example) --------------------------------------------------------------------------------------------------- The example below shows the structure of a SOL transfer instruction. Kit Legacy Rust import { generateKeyPairSigner, lamports } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; // Generate sender and recipient keypairs const sender \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); // Define the amount to transfer const LAMPORTS\_PER\_SOL \= 1\_000\_000\_000n; const transferAmount \= lamports(LAMPORTS\_PER\_SOL / 100n); // 0.01 SOL // Create a transfer instruction for transferring SOL from sender to recipient const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount }); console.log(JSON.stringify(transferInstruction, null, 2)); Console RunClick to execute the code. Kit Legacy Rust import { generateKeyPairSigner, lamports } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; // Generate sender and recipient keypairs const sender \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); // Define the amount to transfer const LAMPORTS\_PER\_SOL \= 1\_000\_000\_000n; const transferAmount \= lamports(LAMPORTS\_PER\_SOL / 100n); // 0.01 SOL // Create a transfer instruction for transferring SOL from sender to recipient const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount }); console.log(JSON.stringify(transferInstruction, null, 2)); Console RunClick to execute the code. The code below shows the output from the previous code snippets. The format will differ between SDKs, but notice that each instruction contains the same three pieces of required information: `program_id`, `accounts`, `data`. Kit Legacy Rust { "accounts": \[\ \ {\ \ "address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC",\ \ "role": 3,\ \ "signer": {\ \ "address": "Hu28vRMGWpQXN56eaE7jRiDDRRz3vCXEs7EKHRfL6bC",\ \ "keyPair": {\ \ "privateKey": {},\ \ "publicKey": {}\ \ }\ \ }\ \ },\ \ {\ \ "address": "2mBY6CTgeyJNJDzo6d2Umipw2aGUquUA7hLdFttNEj7p",\ \ "role": 1\ \ }\ \ \], "programAddress": "11111111111111111111111111111111", "data": { "0": 2, "1": 0, "2": 0, "3": 0, "4": 128, "5": 150, "6": 152, "7": 0, "8": 0, "9": 0, "10": 0, "11": 0 } } The examples below show how to manually build the transfer instruction. (The `Expanded Instruction` tab is functionally equivalent to the `Instruction` tab.) In practice, you usually don’t have to construct an `Instruction` manually. Most programs provide client libraries with helper functions that create the instructions for you. If a library isn't available, you can manually build the instruction. KitLegacyRust Instruction Expanded Instruction const transferAmount \= 0.01; // 0.01 SOL const transferInstruction \= getTransferSolInstruction({ source: sender, destination: recipient.address, amount: transferAmount \* LAMPORTS\_PER\_SOL }); Is this page helpful? [Previous\ \ Accounts](https://solana.com/docs/core/accounts) [Next\ \ Transactions](https://solana.com/docs/core/transactions) ### Table of Contents [SOL transfer example](https://solana.com/docs/core/instructions#sol-transfer-example) [Instructions](https://solana.com/docs/core/instructions#instructions) [Program ID](https://solana.com/docs/core/instructions#program-id) [Account metadata](https://solana.com/docs/core/instructions#account-metadata) [Data](https://solana.com/docs/core/instructions#data) [Create instruction example](https://solana.com/docs/core/instructions#create-instruction-example) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/core/instructions.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Instructions | Solana --- # Cross Program Invocation | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Quick Start](https://solana.com/docs/intro/quick-start) [Cross Program Invocation](https://solana.com/docs/intro/quick-start/cross-program-invocation) =============================================================================================== Copy MarkdownOpen In this section, the CRUD program from the previous PDA section gets updated by adding Cross Program Invocations (CPIs), a feature that enables Solana programs to invoke each other. This tutorial also shows how programs can "sign" for Program Derived Addresses (PDAs) when making Cross Program Invocations. The `update` and `delete` instructions need modification to handle SOL transfers between accounts by invoking the System Program. The purpose of this section includes walking through the process of implementing CPIs in a Solana program using the Anchor framework, building upon the PDA concepts explored in the previous section. For more details, refer to the [Cross Program Invocation](https://solana.com/docs/core/cpi) page. For reference, this link includes the [final code](https://beta.solpg.io/668304cfcffcf4b13384d20a) after completing both the PDA and CPI sections. The [starter code](https://beta.solpg.io/679d75eecffcf4b13384d604) for this section includes just the PDA section completed. ### [Update the Update Instruction](https://solana.com/docs/intro/quick-start/cross-program-invocation#update-the-update-instruction) First, the program needs a simple "pay-to-update" mechanism by changing the `Update` struct and `update` function. Begin by updating the `lib.rs` file to bring into scope items from the `system_program` module. lib.rs use anchor\_lang::system\_program::{transfer, Transfer}; ### Diff Next, update the `Update` struct to include a new account called `vault_account`. This account, controlled by the program, receives SOL from a user when they update their message account. lib.rs #\[account(\ \ mut,\ \ seeds \= \[b"vault", user.key().as\_ref()\],\ \ bump,\ \ )\] pub vault\_account: SystemAccount<'info\>, ### Diff ### Explanation Next, add the CPI logic in the `update` instruction to transfer 0.001 SOL from the user's account to the vault account. lib.rs let transfer\_accounts \= Transfer { from: ctx.accounts.user.to\_account\_info(), to: ctx.accounts.vault\_account.to\_account\_info(), }; let cpi\_context \= CpiContext::new( ctx.accounts.system\_program.to\_account\_info(), transfer\_accounts, ); transfer(cpi\_context, 1\_000\_000)?; ### Diff ### Explanation Rebuild the program. Terminal $ build Copy ### [Update the Delete Instruction](https://solana.com/docs/intro/quick-start/cross-program-invocation#update-the-delete-instruction) Now add a "refund on delete" mechanism by changing the `Delete` struct and `delete` function. First, update the `Delete` struct to include the `vault_account`. This allows the transfer of any SOL in the vault back to the user when they close their message account. lib.rs #\[account(\ \ mut,\ \ seeds \= \[b"vault", user.key().as\_ref()\],\ \ bump,\ \ )\] pub vault\_account: SystemAccount<'info\>, Also add the `system_program` as the CPI for the transfer requires invoking the System Program. lib.rs pub system\_program: Program<'info, System\>, ### Diff ### Explanation Next, add the CPI logic in the `delete` instruction to transfer SOL from the vault account back to the user's account. lib.rs let user\_key \= ctx.accounts.user.key(); let signer\_seeds: &\[&\[&\[u8\]\]\] \= &\[&\[b"vault", user\_key.as\_ref(), &\[ctx.bumps.vault\_account\]\]\]; let transfer\_accounts \= Transfer { from: ctx.accounts.vault\_account.to\_account\_info(), to: ctx.accounts.user.to\_account\_info(), }; let cpi\_context \= CpiContext::new( ctx.accounts.system\_program.to\_account\_info(), transfer\_accounts, ).with\_signer(signer\_seeds); transfer(cpi\_context, ctx.accounts.vault\_account.lamports())?; Note that `_ctx: Context` changes to `ctx: Context` to use the context in the body of the function. ### Diff ### Explanation Rebuild the program. Terminal $ build Copy ### [Redeploy Program](https://solana.com/docs/intro/quick-start/cross-program-invocation#redeploy-program) After making these changes, redeploy the updated program. This ensures the modified program becomes available for testing. On Solana, updating a program simply requires deploying the program at the same program ID. Ensure your Playground wallet has devnet SOL. Get devnet SOL from the [Solana Faucet](https://faucet.solana.com/) . Terminal $ deploy Copy \[show output\] ### Explanation ### [Update Test File](https://solana.com/docs/intro/quick-start/cross-program-invocation#update-test-file) Next, update the `anchor.test.ts` file to include the new vault account in the instructions. This requires deriving the vault PDA and including it in the update and delete instruction calls. #### [Derive Vault PDA](https://solana.com/docs/intro/quick-start/cross-program-invocation#derive-vault-pda) First, add the vault PDA derivation: anchor.test.ts const \[vaultPda, vaultBump\] \= PublicKey.findProgramAddressSync( \[Buffer.from("vault"), wallet.publicKey.toBuffer()\], program.programId ); ### Diff #### [Change Update Test](https://solana.com/docs/intro/quick-start/cross-program-invocation#change-update-test) Then, update the update instruction to include the `vaultAccount` anchor.test.ts const transactionSignature \= await program.methods .update(message) .accounts({ messageAccount: messagePda, vaultAccount: vaultPda }) .rpc({ commitment: "confirmed" }); ### Diff #### [Change Delete Test](https://solana.com/docs/intro/quick-start/cross-program-invocation#change-delete-test) Then, update the delete instruction to include the `vaultAccount` anchor.test.ts const transactionSignature \= await program.methods .delete() .accounts({ messageAccount: messagePda, vaultAccount: vaultPda }) .rpc({ commitment: "confirmed" }); ### Diff ### [Rerun Test](https://solana.com/docs/intro/quick-start/cross-program-invocation#rerun-test) After making these changes, run the tests to ensure everything works as expected: Terminal $ test Copy \[show output\] You can then inspect the SolanaFM links to view the transaction details, where you'll find the CPIs for the transfer instructions within the update and delete instructions. Update CPI Delete CPI If you encounter any errors, you can reference the [final code](https://beta.solpg.io/668304cfcffcf4b13384d20a) . [Next Steps](https://solana.com/docs/intro/quick-start/cross-program-invocation#next-steps) -------------------------------------------------------------------------------------------- Congratulations on completing the Solana Quickstart guide. You've gained hands-on experience with key Solana concepts including: * Fetching and reading data from accounts * Building and sending transactions * Deploying and updating Solana programs * Working with Program Derived Addresses (PDAs) * Making Cross-Program Invocations (CPIs) To deepen your understanding of these concepts, check out the [Core Concepts](https://solana.com/docs/core/accounts) documentation which provides detailed explanations of the topics covered in this guide. ### [Explore More Examples](https://solana.com/docs/intro/quick-start/cross-program-invocation#explore-more-examples) If you prefer learning by example, check out the [Program Examples Repository](https://github.com/solana-developers/program-examples) for a variety of example programs. Solana Playground offers a convenient feature allowing you to import or view projects using their GitHub links. For example, open this [Solana Playground link](https://beta.solpg.io/https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana/anchor) to view the Anchor project from this [Github repo](https://github.com/solana-developers/program-examples/tree/main/basics/hello-solana/anchor) . Click the `Import` button and enter a project name to add it to your list of projects in Solana Playground. Once a project gets imported, all changes receive automatic saving and persistence. Is this page helpful? [Previous\ \ Creating Deterministic Accounts](https://solana.com/docs/intro/quick-start/program-derived-address) [Next\ \ Core Concepts](https://solana.com/docs/core) ### Table of Contents [Update the Update Instruction](https://solana.com/docs/intro/quick-start/cross-program-invocation#update-the-update-instruction) [Update the Delete Instruction](https://solana.com/docs/intro/quick-start/cross-program-invocation#update-the-delete-instruction) [Redeploy Program](https://solana.com/docs/intro/quick-start/cross-program-invocation#redeploy-program) [Update Test File](https://solana.com/docs/intro/quick-start/cross-program-invocation#update-test-file) [Derive Vault PDA](https://solana.com/docs/intro/quick-start/cross-program-invocation#derive-vault-pda) [Change Update Test](https://solana.com/docs/intro/quick-start/cross-program-invocation#change-update-test) [Change Delete Test](https://solana.com/docs/intro/quick-start/cross-program-invocation#change-delete-test) [Rerun Test](https://solana.com/docs/intro/quick-start/cross-program-invocation#rerun-test) [Next Steps](https://solana.com/docs/intro/quick-start/cross-program-invocation#next-steps) [Explore More Examples](https://solana.com/docs/intro/quick-start/cross-program-invocation#explore-more-examples) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/quick-start/cross-program-invocation.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Staking on Solana | Solana [Solana Documentation](https://solana.com/docs) References [Staking on Solana](https://solana.com/docs/references/staking) ================================================================ Copy MarkdownOpen _Note before reading: All references to increases in values are in absolute terms with regards to balance of SOL. This document makes no suggestion as to the monetary value of SOL at any time._ By staking your SOL tokens, you help secure the network and [earn rewards](https://docs.anza.xyz/implemented-proposals/staking-rewards) while doing so. You can stake by delegating your tokens to validators who process transactions and run the network. Delegating stake is a shared-risk shared-reward financial model that may provide returns to holders of tokens delegated for a long period. This is achieved by aligning the financial incentives of the token-holders (delegators) and the validators to whom they delegate. The more stake delegated to a validator, the more often this validator is chosen to write new transactions to the ledger. The more transactions the validator writes, the more rewards the validator and its delegators earn. Validators who configure their systems to be able to process more transactions earn proportionally more rewards and because they keep the network running as fast and as smoothly as possible. Validators incur costs by running and maintaining their systems, and this is passed on to delegators in the form of a fee collected as a percentage of rewards earned. This fee is known as a _commission_. Since validators earn more rewards the more stake is delegated to them, they may compete with one another to offer the lowest commission for their services. Although this is not implemented in the Solana protocol today, in the future, delegators could risk losing tokens when staking through a process known as _slashing_. Slashing involves the removal and destruction of a portion of a validator's SOL in response to intentional malicious behavior, such as creating invalid transactions or censoring certain types of transactions or network participants. There is no in protocol implementation of slashing currently. For more information on slashing see the [slashing roadmap](https://docs.anza.xyz/proposals/optimistic-confirmation-and-slashing#slashing-roadmap) . [How do I stake my SOL tokens?](https://solana.com/docs/references/staking#how-do-i-stake-my-sol-tokens) --------------------------------------------------------------------------------------------------------- You can stake SOL by moving your tokens into a wallet that supports staking. The wallet provides steps to create a stake account and do the delegation. ### [Supported Wallets](https://solana.com/docs/references/staking#supported-wallets) Many web and mobile wallets support Solana staking operations. Please check with your favorite wallet's maintainers regarding status ### [Solana command line tools](https://solana.com/docs/references/staking#solana-command-line-tools) * Solana command line tools can perform all stake operations in conjunction with a CLI-generated keypair file wallet, a paper wallet, or with a connected Ledger Nano. [Staking commands using the Solana Command Line Tools](https://docs.anza.xyz/cli/examples/delegate-stake) . ### [Create a Stake Account](https://solana.com/docs/references/staking#create-a-stake-account) Follow the wallet's instructions for creating a staking account. This account will be of a different type than one used to simply send and receive tokens. ### [Select a Validator](https://solana.com/docs/references/staking#select-a-validator) Follow the wallet's instructions for selecting a validator. You can get information about potentially performant validators from the links below. The Solana Foundation does not recommend any particular validator. The site solanabeach.io is built and maintained by one of our validators, Staking Facilities. It provides a some high-level graphical information about the network as a whole, as well as a list of each validator and some recent performance statistics about each one. * [https://solanabeach.io](https://solanabeach.io/) To view block production statistics, use the Solana command-line tools: * `solana validators` * `solana block-production` The Solana team does not make recommendations on how to interpret this information. Do your own due diligence. ### [Delegate your Stake](https://solana.com/docs/references/staking#delegate-your-stake) Follow the wallet's instructions for delegating your stake to your chosen validator. Is this page helpful? [Previous\ \ RPC Endpoints](https://solana.com/docs/references/clusters) [Next\ \ Stake Accounts](https://solana.com/docs/references/staking/stake-accounts) ### Table of Contents [How do I stake my SOL tokens?](https://solana.com/docs/references/staking#how-do-i-stake-my-sol-tokens) [Supported Wallets](https://solana.com/docs/references/staking#supported-wallets) [Solana command line tools](https://solana.com/docs/references/staking#solana-command-line-tools) [Create a Stake Account](https://solana.com/docs/references/staking#create-a-stake-account) [Select a Validator](https://solana.com/docs/references/staking#select-a-validator) [Delegate your Stake](https://solana.com/docs/references/staking#delegate-your-stake) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/references/staking/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Solana Gaming SDKs | Solana [Solana Documentation](https://solana.com/docs) Solana SDKsCommunity SDKs [Solana Gaming SDKs](https://solana.com/docs/clients/community/game-sdks) ========================================================================== Copy MarkdownOpen With Solana being a high performance blockchain with low fees and fast transactions, a great game developer community has formed around it. Here you can find details about the Solana game development SDKs available within the ecosystem. All the SDKs are open source and community built. If you are working on a SDK yourself feel free to open a PR to this page and add it. [Unity SDK](https://solana.com/docs/clients/community/game-sdks#unity-sdk) --------------------------------------------------------------------------- The Unity game engine is known for its beginner friendly approach and cross platform support including WebGL, iOS, and Android. Build once, export everywhere. * [Docs](https://docs.magicblock.gg/introduction) * [Source](https://github.com/magicblock-labs/Solana.Unity-SDK) * [Example Games](https://github.com/solana-developers/solana-game-examples) * [Tic Tac Toe](https://blog.magicblock.gg/bolt-tic-tac-toe/) The Solana Unity SDK is maintained by [Magicblock](https://www.magicblock.gg/) and comes with: * NFT support * Candy machine integration * Transactions * RPC functions * Phantom deep links * WebGL connector * Reliable WebSocket connection support * Mobile wallet-adapter * Sessions keys for auto approving transaction * Anchor client code generation and more. [Godot SDK](https://solana.com/docs/clients/community/game-sdks#godot-sdk) --------------------------------------------------------------------------- The [Godot Engine](https://godotengine.org/) is an open source game engine which gained lots of support in the last few years. The Solana SDK for Godot is maintained by [ZenRepublic](https://twitter.com/ZenRepublicNDM) and [Virus-Axel](https://twitter.com/AxelBenjam) . It comes with a wallet adapter integration, transactions, RPC functions, and Anchor client code generation. Even a fully functional Metaplex [candy machine integration](https://zenwiki.gitbook.io/solana-godot-sdk-docs/guides/setup-candy-machine) . * [Solana Godot Engine SDK](https://github.com/Virus-Axel/godot-solana-sdk) * [Docs](https://zenwiki.gitbook.io/solana-godot-sdk-docs) * [Demo](https://github.com/ZenRepublic/GodotSolanaSDKDemoPackage) * [Tutorial](https://www.youtube.com/watch?v=tszFPInYmXQ) * [Maintainer](https://twitter.com/ZenRepublicNDM) [Turbo.Computer - Rust Game Engine](https://solana.com/docs/clients/community/game-sdks#turbocomputer---rust-game-engine) -------------------------------------------------------------------------------------------------------------------------- Turbo is a rust game engine written from the ground up to focus on Solana, with a lightweight architecture and fast iteration times. It is beginner friendly and comes with full Solana RPC support. You can even use its AI tools to generate complete games. * [Website](https://turbo.computer/) * [Docs](https://docs.turbo.computer/) * [Twitter account](https://twitter.com/makegamesfast) * [Maintainer](https://twitter.com/jozanza) [Honeycomb Protocol](https://solana.com/docs/clients/community/game-sdks#honeycomb-protocol) ============================================================================================= Honeycomb provides a suite of onchain programs and state-compression tools that handle all crucial game lifecycle functions and composability within the Solana Virtual Machine (SVM). It supports lots of NFT functionality like staking, missions, loot boxes, player profiles, state compression, auto approving transactions and more. * [Twitter account](https://twitter.com/honeycomb_prtcl) * [Docs](https://docs.honeycombprotocol.com/) [Unreal SDKs](https://solana.com/docs/clients/community/game-sdks#unreal-sdks) =============================================================================== Unreal Engine is known for its great visuals and node based scripting framework. There are multiple Solana SDKs maintained by different companies. ### [Varmeta Unreal SDK](https://solana.com/docs/clients/community/game-sdks#varmeta-unreal-sdk) VAR META provides an open-source Unreal SDK for integrating Solana blockchain functionality into Unreal Engine projects. It enables developers to interact with Solana's smart contracts, manage wallets, and execute transactions directly within Unreal Engine. * [Unreal SDK by Varmeta](https://github.com/VAR-META-Tech/UnrealSolanaSDK) * [Maintainer](https://www.var-meta.com/) ### [Bitfrost Unreal SDK](https://solana.com/docs/clients/community/game-sdks#bitfrost-unreal-sdk) Bitfrost is working on an Unreal SDK which was already used in multiple games built during recent Solana game jams. It comes with C# `solnet` support in C++ and Blueprints, minting of metaplex NFTs, payment processor examples in game wallet and more. * [Solana Unreal SDK by Bitfrost](https://github.com/Bifrost-Technologies/Solana-Unreal-SDK) * [Tutorial](https://www.youtube.com/watch?v=S8fm8mFeUkk) * [Maintainer](https://twitter.com/BifrostTitan) ### [Thugz Unreal SDK](https://solana.com/docs/clients/community/game-sdks#thugz-unreal-sdk) Thugz is a tech studio and NFT project which is also maintaining on open source an Unreal SDK for Solana. It comes with lots of NFT focused functionality and the plugin is compatible with iOS and Android too. * [Thugz Blockchain plugin](https://www.fab.com/listings/a7e220ba-93e5-4a3b-99e7-17b13da76f05) * [Repository](https://github.com/ThugzLabs/Thugz-BC-Plugin-Packaged-for-UE5.4) * [Documentation](https://thugzblockchainplugin-docs.vercel.app/) * [Video Tutorial](https://www.youtube.com/watch?v=dS7sTZd_E9U&ab_channel=ThugzNFT) ### [Star Atlas Foundation Kit](https://solana.com/docs/clients/community/game-sdks#star-atlas-foundation-kit) The [Star Atlas](https://staratlas.com/) team open sourced some of their SDK stack called _Foundation Kit_. It is not actively maintained but can be a starting point for your project. * [Star Atlas Unreal SDK](https://github.com/staratlasmeta/FoundationKit) * [Tutorial](https://www.youtube.com/watch?v=S8fm8mFeUkk) [Next.js/React + Anchor](https://solana.com/docs/clients/community/game-sdks#nextjsreact--anchor) -------------------------------------------------------------------------------------------------- One of the easiest way to build on Solana is using the Web3js JavaScript framework in combination with the Solana Anchor framework. For more complex games, we recommend looking into using a Game Engine like [Unity](https://solana.com/docs/clients/community/game-sdks#unity-sdk) or [Unreal](https://solana.com/docs/clients/community/game-sdks#unreal-sdks) though. The fastest way to set it up a Next.js based game: npx create-solana-game your-game-name This will generate a great starting application with `wallet-adapter` support, an Anchor program, a React app, and a Unity client already configured to work together. A benefit of using Next.js is that you can use the same code in the backend and in the frontend, speeding up development. * [Web3.js](https://solana.com/docs/clients/javascript) * [Video Tutorial](https://www.youtube.com/watch?v=fnhivg_pemI&t=1s&ab_channel=Solana) > If you are working on a Solana SDK and want to add your preset to the preset you can open a PR here: [Solana games preset](https://github.com/solana-developers/solana-game-preset) [Phaser](https://solana.com/docs/clients/community/game-sdks#phaser) --------------------------------------------------------------------- A fast, free, and fun open source framework for Canvas and WebGL powered browser based games. [Phaser](https://phaser.io/) is a great way to get started with game development on Solana. The Phaser Solana Platformer Template is a great starting point for your game. * [Source Code](https://github.com/Bread-Heads-NFT/solana-phaser-template) * [Maintainer](https://twitter.com/blockiosaurus) [Flutter](https://solana.com/docs/clients/community/game-sdks#flutter) ----------------------------------------------------------------------- Flutter is an open source framework, maintained by Google, for building beautiful, natively compiled, multi-platform applications from a single codebase. The Solana Flutter SDK is maintained by the [Espresso Cash](https://www.espressocash.com/) team. * [Source Code](https://github.com/espresso-cash/espresso-cash-public) [Python](https://solana.com/docs/clients/community/game-sdks#python) --------------------------------------------------------------------- Python is an easy to learn programming and widely used language (often used in machine learning applications). The Seahorse framework enables developers to write Solana programs in Python. Seahorse is built on top of the Anchor framework and converts Python code into Anchor based rust code. Seahorse is currently in beta. * [Documentation](https://www.seahorse.dev/) * [Github Repo](https://github.com/solana-developers/seahorse) * [Anchor Playground Example](https://beta.solpg.io/tutorials/hello-seahorse) [Native C#](https://solana.com/docs/clients/community/game-sdks#native-c) -------------------------------------------------------------------------- The original port of Web3js to C#. It comes with a bunch of functionality like transactions, RPC functions and Anchor client code generation. * [Source and Docs](https://github.com/bmresearch/Solnet/blob/master/docs/articles/getting_started.md) Is this page helpful? [Previous\ \ Go SDK](https://solana.com/docs/clients/community/go) [Next\ \ RPC Endpoints](https://solana.com/docs/references/clusters) ### Table of Contents [Unity SDK](https://solana.com/docs/clients/community/game-sdks#unity-sdk) [Godot SDK](https://solana.com/docs/clients/community/game-sdks#godot-sdk) [Turbo.Computer - Rust Game Engine](https://solana.com/docs/clients/community/game-sdks#turbocomputer---rust-game-engine) [Honeycomb Protocol](https://solana.com/docs/clients/community/game-sdks#honeycomb-protocol) [Unreal SDKs](https://solana.com/docs/clients/community/game-sdks#unreal-sdks) [Varmeta Unreal SDK](https://solana.com/docs/clients/community/game-sdks#varmeta-unreal-sdk) [Bitfrost Unreal SDK](https://solana.com/docs/clients/community/game-sdks#bitfrost-unreal-sdk) [Thugz Unreal SDK](https://solana.com/docs/clients/community/game-sdks#thugz-unreal-sdk) [Star Atlas Foundation Kit](https://solana.com/docs/clients/community/game-sdks#star-atlas-foundation-kit) [Next.js/React + Anchor](https://solana.com/docs/clients/community/game-sdks#nextjsreact--anchor) [Phaser](https://solana.com/docs/clients/community/game-sdks#phaser) [Flutter](https://solana.com/docs/clients/community/game-sdks#flutter) [Python](https://solana.com/docs/clients/community/game-sdks#python) [Native C#](https://solana.com/docs/clients/community/game-sdks#native-c) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/clients/community/game-sdks.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # How Payments Work on Solana | Solana [Payments](https://solana.com/docs) [How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) ================================================================================== Copy MarkdownOpen Before building payment flows on Solana, you'll need to understand five core concepts: wallets, stablecoins, token accounts, fees, and transactions. Solana payments map cleanly to multi-currency payment systems: | Traditional Payment Model | Solana | Description | | --- | --- | --- | | Customer ID / Account number | Wallet address | Unique identifier for an account holder | | Currency (USD, EUR) | Token Mint (USDG, USDC) | The asset type being transferred | | Balance by currency | Token Account (ATA) | Holds a balance of a specific currency/mint | Just as a bank customer has a single identity but holds separate balances for each currency, a Solana wallet has one address but a distinct token account for each asset it holds. Let's break down each component. [Wallets: Senders and Receivers](https://solana.com/docs/payments/how-payments-work#wallets-senders-and-receivers) ------------------------------------------------------------------------------------------------------------------- Every payment involves two parties, each identified by a **wallet address**—a unique 32-byte public key (e.g., `7EcDhS...`). * **Sender**: The wallet initiating the payment. Must hold sufficient stablecoin account balance and sign the transaction. * **Receiver**: The destination wallet. Does not need to sign or hold an existing balance. * **Fee Payer**: The optional fee payer wallet. Can be used to subsidize or enable stablecoin-only transactions between users. Think of wallet addresses like bank account numbers: public, safe to share, and required to send or receive funds. [Stablecoins](https://solana.com/docs/payments/how-payments-work#stablecoins) ------------------------------------------------------------------------------ Stablecoins are referred to as "tokens" on Solana. Tokens represent an asset type on the network. Each token has a unique identifier called a "mint address". When building payment systems, you'll reference these mint addresses to identify the asset you are interacting with. Here are some common stablecoin mints on mainnet: | Token | Issuer | Mint Address | | --- | --- | --- | | USDC | Circle | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | | USDT | Tether | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` | | PYUSD | PayPal | `2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo` | | USDG | Paxos | `2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH` | For more information on stablecoins on Solana, see the [Stablecoins](https://solana.com/solutions/stablecoins) solution page. When accepting payments, always validate the mint address and token program. Tokens can share names but have different issuers and underlying assets. [Token Accounts](https://solana.com/docs/payments/how-payments-work#token-accounts) ------------------------------------------------------------------------------------ Wallets don't hold tokens directly. Instead, each wallet has authority over a **token account** for each type of token it holds. Payments are made by transferring tokens from a sender's token account to a receiver's token account of the same mint: Token Accounts An **Associated Token Account** is a deterministic token account tied to a specific wallet and mint. Given a wallet address and mint, the ATA address is always the same. 1. **One ATA per mint**. A wallet has exactly one ATA for USDC, one for USDT, etc. 2. **Must exist before receiving**. You cannot send tokens to an ATA that doesn't exist. 3. **Sender typically creates**. If the receiver's ATA doesn't exist, the sender can create it as part of the payment transaction. import { findAssociatedTokenPda } from "@solana-program/token"; const \[receiverATA\] \= await findAssociatedTokenPda({ mint: USDG\_MINT\_ADDRESS, owner: receiverWallet.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); [Token Programs](https://solana.com/docs/payments/how-payments-work#token-programs) ------------------------------------------------------------------------------------ On Solana, programs are executable logic that govern account state. Token accounts are managed by a **Token Program**—the on-chain code that verifies transfers and updates balances atomically. Solana has two token programs: | Program | Address | Example Tokens that use this program | | --- | --- | --- | | **Token Program** | `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` | USDC, USDT | | **Token-2022** | `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` | PYUSD, USDG | Token-2022 (also called "Token Extensions") adds features like transfer hooks, transfer fees, and confidential transfers. Both programs work similarly for basic transfers, but you must use the correct one when deriving ATAs. ### [Why This Matters](https://solana.com/docs/payments/how-payments-work#why-this-matters) The Token Program used to create a token governs the instructions and account state for the token. If you use the wrong program, you will not be able to transfer the token. ATAs are derived from three inputs: `wallet + mint + token_program`. Using the wrong program produces an **entirely different address**: import { findAssociatedTokenPda, TOKEN\_PROGRAM\_ADDRESS } from "@solana-program/token"; import { TOKEN\_2022\_PROGRAM\_ADDRESS } from "@solana-program/token-2022"; // USDC uses Token Program const \[usdcAta\] \= await findAssociatedTokenPda({ mint: USDC\_MINT, owner: walletAddress, tokenProgram: TOKEN\_PROGRAM\_ADDRESS // ✓ Correct }); // ❌ This will produce a different address because it uses the wrong program const \[wrongUsdcAta\] \= await findAssociatedTokenPda({ mint: USDC\_MINT, owner: walletAddress, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS // ❌ Wrong program }); // PYUSD uses Token-2022 const \[pyusdAta\] \= await findAssociatedTokenPda({ mint: PYUSD\_MINT, owner: walletAddress, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS // ✓ Correct }); Deriving an ATA with the wrong program will produce an invalid address. Always match the program to the token's mint. The same principle applies to transfer instructions. Each token program has its own transfer instruction, and you must invoke the correct one: import { getTransferInstruction } from "@solana-program/token"; import { getTransferInstruction as getTransferInstruction22 } from "@solana-program/token-2022"; // For USDC (Token Program) const usdcTransferIx \= getTransferInstruction({ source: senderUsdcAta, destination: receiverUsdcAta, authority: senderWallet, amount: 1\_000\_000n // 1 USDC (6 decimals) }); // For PYUSD (Token-2022) const pyusdTransferIx \= getTransferInstruction22({ source: senderPyusdAta, destination: receiverPyusdAta, authority: senderWallet, amount: 1\_000\_000n // 1 PYUSD (6 decimals) }); // \*Note\*: Most token program JS Client functions include the ability // to specify the token program address. Generally, defining it is a // good practice to ensure you are fully aware of the program you are using const usdcTransferIx2 \= getTransferInstruction( { source: senderUsdcAta, destination: receiverUsdcAta, authority: senderWallet, amount: 1\_000\_000n // 1 USDC (6 decimals) }, { tokenProgram: TOKEN\_PROGRAM\_ADDRESS } ); Sending a transfer instruction to the wrong program will fail. The program validates that it owns the token accounts involved—accounts created by Token Program cannot be transferred via Token-2022, and vice versa. To verify which program a token or token account uses, fetch the mint or token account and check its `owner` field: import { createSolanaRpc, address } from "@solana/kit"; const rpc \= createSolanaRpc("https://api.mainnet-beta.solana.com"); const accountInfo \= await rpc.getAccountInfo(address(mintAddress)).send(); // The owner field tells you which program manages this token const tokenProgram \= accountInfo.value?.owner; // Returns: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (Token Program) // or: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb (Token-2022) For payment applications, store the correct program address alongside each supported token: const SUPPORTED\_TOKENS \= { USDC: { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", program: TOKEN\_PROGRAM\_ADDRESS, decimals: 6 }, PYUSD: { mint: "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", program: TOKEN\_2022\_PROGRAM\_ADDRESS, decimals: 6 } }; ### [Token Extensions](https://solana.com/docs/payments/how-payments-work#token-extensions) The Token Extensions Program (Token 2022) provides more features through extra instructions referred to as extensions. Extensions are optional features you can add to a token mint or token account. For more information on Token Extensions, see the [Token Extensions](https://solana.com/docs/tokens/extensions) documentation. [Fees](https://solana.com/docs/payments/how-payments-work#fees) ---------------------------------------------------------------- Solana payments involve up to three cost components: | Fee Type | SOL | USD (est.) | When | | --- | --- | --- | --- | | **Base transaction fee** | 5,000 lamports\* | ~$0.0007 | Every transaction (bundle multiple payments to amortize) | | **Priority fee** | Variable | Variable | Optional; faster inclusion during congestion | | **Account creation (rent)** | ~0.0029 SOL | ~$0.40 | Only when creating a new token account | **Total cost per payment**: Under $0.001 for most transfers. If creating a new token account, expect ~$0.40 total. Solana uses [local fee markets](https://github.com/solana-foundation/solana-improvement-documents/pull/436) —each program's transactions compete only with other transactions targeting the same state. This means payment fees stay low and predictable even during periods of high network activity elsewhere. Rent costs are also [planned to decrease 50% in the near future](https://github.com/solana-foundation/solana-improvement-documents/pull/436) . You can abstract fees entirely so users never interact with SOL. See [Fee Abstraction](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction) for implementation patterns. [Transactions and Instructions](https://solana.com/docs/payments/how-payments-work#transactions-and-instructions) ------------------------------------------------------------------------------------------------------------------ A transaction is the atomic unit of execution on Solana—either every operation succeeds, or none do. Each transaction contains one or more instructions, which are individual commands (e.g., "transfer 10 USDC," "create token account"). A typical payment transaction might include two instructions: create the receiver's token account (if needed), then transfer tokens. Both execute atomically—no partial states. As you will see in [Payment Processing](https://solana.com/docs/payments/send-payments/payment-processing) , you can bundle multiple payments into a single transaction to reduce costs and increase throughput. [Putting It Together](https://solana.com/docs/payments/how-payments-work#putting-it-together) ---------------------------------------------------------------------------------------------- A typical payment flow: 1. **Gather input**. Get sender and receiver wallet addresses and the mint address of the token being transferred. 2. **Derive ATAs**. Determine the token accounts for both parties. 3. **Build and sign**. Construct the transaction with necessary transfer instructions, sign with the sender's key. 4. **Send & Confirm**. Transaction settles in under a second. [Next Steps](https://solana.com/docs/payments/how-payments-work#next-steps) ---------------------------------------------------------------------------- [### Interacting with Solana\ \ Connect to the network and explore Solana payment data.](https://solana.com/docs/payments/interacting-with-solana) [### Send your first payment\ \ Build and send a stablecoin transfer.](https://solana.com/docs/payments/send-payments) \* a lamport is the smallest unit of SOL and is equal to 0.000000001 SOL Is this page helpful? [Next\ \ Interacting with Solana](https://solana.com/docs/payments/interacting-with-solana) ### Table of Contents [Wallets: Senders and Receivers](https://solana.com/docs/payments/how-payments-work#wallets-senders-and-receivers) [Stablecoins](https://solana.com/docs/payments/how-payments-work#stablecoins) [Token Accounts](https://solana.com/docs/payments/how-payments-work#token-accounts) [Token Programs](https://solana.com/docs/payments/how-payments-work#token-programs) [Why This Matters](https://solana.com/docs/payments/how-payments-work#why-this-matters) [Token Extensions](https://solana.com/docs/payments/how-payments-work#token-extensions) [Fees](https://solana.com/docs/payments/how-payments-work#fees) [Transactions and Instructions](https://solana.com/docs/payments/how-payments-work#transactions-and-instructions) [Putting It Together](https://solana.com/docs/payments/how-payments-work#putting-it-together) [Next Steps](https://solana.com/docs/payments/how-payments-work#next-steps) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/how-payments-work.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter How Payments Work on Solana | Solana --- # Common JSON Data Structures for Solana RPC Methods | Solana [Solana Documentation](https://solana.com/docs) [Solana RPC Methods](https://solana.com/docs/rpc) [Common JSON Data Structures for Solana RPC Methods](https://solana.com/docs/rpc/json-structures) ================================================================================================== Copy MarkdownOpen Various Solana RPC methods will return more complex responses as structured JSON objects, filled with specific keyed values. The most common of these JSON data structures include: * [transactions](https://solana.com/docs/rpc/json-structures#transactions) * [inner instructions](https://solana.com/docs/rpc/json-structures#inner-instructions) * [token balances](https://solana.com/docs/rpc/json-structures#token-balances) [Transactions](https://solana.com/docs/rpc/json-structures#transactions) ------------------------------------------------------------------------- Transactions are quite different from those on other blockchains. Be sure to review [Anatomy of a Transaction](https://solana.com/docs/core/transactions) to learn about transactions on Solana. ### [JSON](https://solana.com/docs/rpc/json-structures#json) The JSON structure of a transaction is defined as follows: ### Reference * `message: ` - Defines the content of the transaction. * `accountKeys: ` - List of base-58 encoded public keys used by the transaction, including by the instructions and for signatures. The first `message.header.numRequiredSignatures` public keys must sign the transaction. * `header: ` - Details the account types and signatures required by the transaction. * `numRequiredSignatures: ` - The total number of signatures required to make the transaction valid. The signatures must match the first `numRequiredSignatures` of `message.accountKeys`. * `numReadonlySignedAccounts: ` - The last `numReadonlySignedAccounts` of the signed keys are read-only accounts. Programs may process multiple transactions that load read-only accounts within a single PoH entry, but are not permitted to credit or debit lamports or modify account data. Transactions targeting the same read-write account are evaluated sequentially. * `numReadonlyUnsignedAccounts: ` - The last `numReadonlyUnsignedAccounts` of the unsigned keys are read-only accounts. * `recentBlockhash: ` - A base-58 encoded hash of a recent block in the ledger used to prevent transaction duplication and to give transactions lifetimes. * `instructions: ` - List of program instructions that will be executed in sequence and committed in one atomic transaction if all succeed. * `programIdIndex: ` - Index into the `message.accountKeys` array indicating the program account that executes this instruction. * `accounts: ` - List of ordered indices into the `message.accountKeys` array indicating which accounts to pass to the program. * `data: ` - The program input data encoded in a base-58 string. * `addressTableLookups: ` - List of address table lookups used by a transaction to dynamically load addresses from on-chain address lookup tables. Undefined if `maxSupportedTransactionVersion` is not set. * `accountKey: ` - base-58 encoded public key for an address lookup table account. * `writableIndexes: ` - List of indices used to load addresses of writable accounts from a lookup table. * `readonlyIndexes: ` - List of indices used to load addresses of readonly accounts from a lookup table. * `signatures: ` - A list of base-58 encoded signatures applied to the transaction. The list is always of length `message.header.numRequiredSignatures` and not empty. The signature at index `i` corresponds to the public key at index `i` in `message.accountKeys`. The first one is used as the [transaction id](https://solana.com/docs/references/terminology#transaction-id) . ### [JSON Parsed](https://solana.com/docs/rpc/json-structures#json-parsed) The JSON parsed structure of a transaction follows a similar structure to the regular JSON format, with additional parsing of account and instruction information: ### Reference * `message: ` - Defines the content of the transaction. * `accountKeys: ` - List of account information used by the transaction. * `pubkey: ` - The base-58 encoded public key of the account. * `signer: ` - Indicates if the account is a required transaction signer. * `writable: ` - Indicates if the account is writable. * `source: ` - Source of the account (transaction or lookup table). * `recentBlockhash: ` - A base-58 encoded hash of a recent block in the ledger used to prevent transaction duplication and to give transactions lifetimes. * `instructions: ` - List of parsed program instructions. * `program: ` - The name of the program being called. * `programId: ` - The base-58 encoded public key of the program. * `stackHeight: ` - The stack height of the instruction. * `parsed: ` - Program-specific parsed data. * `type: ` - The type of instruction (e.g., "transfer"). * `info: ` - Parsed instruction information specific to the program and instruction type. * `signatures: ` - A list of base-58 encoded signatures applied to the transaction. [Transaction Status Metadata](https://solana.com/docs/rpc/json-structures#transaction-status-metadata) ------------------------------------------------------------------------------------------------------- ### Reference * `err: ` - Error if transaction failed, null if transaction succeeded. [TransactionError definitions](https://github.com/solana-labs/solana/blob/c0c60386544ec9a9ec7119229f37386d9f070523/sdk/src/transaction/error.rs#L13) * `fee: ` - fee this transaction was charged, as u64 integer * `preBalances: ` - array of u64 account balances from before the transaction was processed * `postBalances: ` - array of u64 account balances after the transaction was processed * `innerInstructions: ` - List of [inner instructions](https://solana.com/docs/rpc/json-structures#inner-instructions) or `null` if inner instruction recording was not enabled during this transaction * `preTokenBalances: ` - List of [token balances](https://solana.com/docs/rpc/json-structures#token-balances) from before the transaction was processed or omitted if token balance recording was not yet enabled during this transaction * `postTokenBalances: ` - List of [token balances](https://solana.com/docs/rpc/json-structures#token-balances) from after the transaction was processed or omitted if token balance recording was not yet enabled during this transaction * `logMessages: ` - array of string log messages or `null` if log message recording was not enabled during this transaction * `rewards: ` - transaction-level rewards; an array of JSON objects containing: * `pubkey: ` - The public key, as base-58 encoded string, of the account that received the reward * `lamports: `\- number of reward lamports credited or debited by the account, as a i64 * `postBalance: ` - account balance in lamports after the reward was applied * `rewardType: ` - type of reward: "fee", "rent", "voting", "staking" * `commission: ` - vote account commission when the reward was credited, only present for voting and staking rewards * DEPRECATED: `status: ` - Transaction status * `"Ok": ` - Transaction was successful * `"Err": ` - Transaction failed with TransactionError * `loadedAddresses: ` - Transaction addresses loaded from address lookup tables. Undefined if `maxSupportedTransactionVersion` is not set in request params, or if `jsonParsed` encoding is set in request params. * `writable: ` - Ordered list of base-58 encoded addresses for writable loaded accounts * `readonly: ` - Ordered list of base-58 encoded addresses for readonly loaded accounts * `returnData: ` - the most-recent return data generated by an instruction in the transaction, with the following fields: * `programId: ` - the program that generated the return data, as base-58 encoded Pubkey * `data: <[string, encoding]>` - the return data itself, as base-64 encoded binary data * `computeUnitsConsumed: ` - number of [compute units](https://solana.com/docs/core/fees#compute-budget) consumed by the transaction * `version: <"legacy"|number|undefined>` - Transaction version. Undefined if `maxSupportedTransactionVersion` is not set in request params. * `signatures: ` - present if "signatures" are requested for transaction details; an array of signatures strings, corresponding to the transaction order in the block [Inner Instructions](https://solana.com/docs/rpc/json-structures#inner-instructions) ------------------------------------------------------------------------------------- When an instruction in a transaction makes a [cross-program invocation](https://solana.com/docs/core/cpi) (CPI), the invoked instructions are detailed under `innerInstructions`. * `index: number` – Index of the instruction at `transaction.message.instructions[index]` that made the CPI. * `instructions: array[object]` – List of CPI instructions invoked by the instruction at `index`, encoded as Json or JsonParsed objects. ### [JSON Parsed](https://solana.com/docs/rpc/json-structures#json-parsed-1) * `program: string` – Name of the program the CPI is being made to. * `programId: string` – Program ID of the program the CPI is being made to. * `parsed` – Parser output when the program is recognized: * `type: string` – Instruction name identified by the parser. * `info: object` – Program specific data returned by the parser. * `stackHeight: number` – CPI depth. ### Reference ### [JSON](https://solana.com/docs/rpc/json-structures#json-1) * `programIdIndex: number` – Index into `transaction.message.accountKeys` of the Program ID for the program the CPI is being made to. * `accounts: array[number]` – Indexes into `transaction.message.accountKeys` for the accounts passed to the program the CPI is being made to. * `data: string` – Base58 encoded instruction data passed to the program the CPI is being made to. * `stackHeight: number` – Depth of the CPI call. ### Reference [Token Balances](https://solana.com/docs/rpc/json-structures#token-balances) ----------------------------------------------------------------------------- ### Reference The JSON structure of token balances is defined as a list of objects in the following structure: * `accountIndex: ` - Index of the account in which the token balance is provided for. * `mint: ` - Pubkey of the token's mint. * `owner: ` - Pubkey of token balance's owner. * `programId: ` - Pubkey of the Token program that owns the account. * `uiTokenAmount: ` - * `amount: ` - Raw amount of tokens as a string, ignoring decimals. * `decimals: ` - Number of decimals configured for token's mint. * `uiAmount: ` - Token amount as a float, accounting for decimals. **DEPRECATED** * `uiAmountString: ` - Token amount as a string, accounting for decimals. Is this page helpful? [Previous\ \ Solana RPC Methods](https://solana.com/docs/rpc) [Next\ \ HTTP Methods](https://solana.com/docs/rpc/http) ### Table of Contents [Transactions](https://solana.com/docs/rpc/json-structures#transactions) [JSON](https://solana.com/docs/rpc/json-structures#json) [JSON Parsed](https://solana.com/docs/rpc/json-structures#json-parsed) [Transaction Status Metadata](https://solana.com/docs/rpc/json-structures#transaction-status-metadata) [Inner Instructions](https://solana.com/docs/rpc/json-structures#inner-instructions) [JSON Parsed](https://solana.com/docs/rpc/json-structures#json-parsed-1) [JSON](https://solana.com/docs/rpc/json-structures#json-1) [Token Balances](https://solana.com/docs/rpc/json-structures#token-balances) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/rpc/json-structures.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Common JSON Data Structures for Solana RPC Methods | Solana --- # Install the dependencies necessary to develop with Solana | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Installation](https://solana.com/docs/intro/installation) [Install Dependencies](https://solana.com/docs/intro/installation/dependencies) ================================================================================ Copy MarkdownOpen A guide to setting up your local Solana development environment. Learn how to install Rust, the Solana CLI, and Anchor Framework on Windows (WSL), Linux, and Mac. Use this guide if you prefer to install each dependency individually, or if the [quick installation](https://solana.com/docs/intro/installation/) fails for any reason. ### [Prerequisites](https://solana.com/docs/intro/installation/dependencies#prerequisites) ### Windows ### Linux ### [Install Rust](https://solana.com/docs/intro/installation/dependencies#install-rust) Developers build Solana programs using the [Rust](https://www.rust-lang.org/) programming language. 1. Install Rust using [rustup](https://www.rust-lang.org/tools/install) by entering the following command in your terminal: Terminal $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y Copy After a successful installation you will see the following message: ### Successful Rust Install Message 2. Reload your PATH environment variable to include [Cargo's](https://github.com/rust-lang/cargo) bin directory: Terminal $ . "$HOME/.cargo/env" Copy 3. Verify that the installation was successful. Terminal $ rustc --version Copy You will see output like the following: rustc 1.86.0 (05f9846f8 2025-03-31) ### [Install Solana CLI](https://solana.com/docs/intro/installation/dependencies#install-solana-cli) The Solana CLI provides all the tools required to build and deploy Solana programs. 1. Install the Solana CLI tool suite by using the official install command: Terminal $ sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" Copy You can replace `stable` with the release tag matching the software version of your desired release (i.e. `v2.0.3`), or use one of the three symbolic channel names: `stable`, `beta`, or `edge`. 2. Add a PATH environment variable A first-time installation of the Solana CLI, may prompt you to add a `PATH` environment variable. To do so, close and reopen your terminal or run the following in your shell: export PATH="/Users/test/.local/share/solana/install/active\_release/bin:$PATH" 3. Update your PATH environment variable Windows & LinuxMac If you are using **Linux** or **WSL**, you must add the Solana CLI binary to your PATH so that the command is available in your terminal. To do so, follow the steps below: **a.** Check which shell you are using: Terminal $ echo $SHELL Copy * If the output contains `/bash`, use `.bashrc`. * If the output contains `/zsh`, use `.zshrc`. **b.** Run the appropriate command, based on your shell. For Bash (`bashrc`): Terminal $ echo 'export PATH="$HOME/.local/share/solana/install/active\_release/bin:$PATH"' >> ~/.bashrc Copy $ source ~/.bashrc Copy For Zsh (`zshrc`): Terminal $ echo 'export PATH="$HOME/.local/share/solana/install/active\_release/bin:$PATH"' >> ~/.zshrc Copy $ source ~/.zshrc Copy 4. Restart your terminal or run the following command to refresh the terminal session: Terminal $ source ~/.bashrc # If using Bash Copy $ source ~/.zshrc # If using Zsh Copy 5. Verify that the installation succeeded by checking the Solana CLI version: Terminal $ solana --version Copy You will see output like the following: solana-cli 2.2.12 (src:0315eb6a; feat:1522022101, client:Agave) You can view all available versions on the [Agave Github repo](https://github.com/anza-xyz/agave/releases) . Agave is the validator client from [Anza](https://www.anza.xyz/) , formerly known as Solana Labs validator client. 5. Update the Solana CLI to the latest version, as needed _(Optional)_ Terminal $ agave-install update Copy ### [Install Anchor CLI](https://solana.com/docs/intro/installation/dependencies#install-anchor-cli) [Anchor](https://www.anchor-lang.com/) is a framework for developing Solana programs. The Anchor framework leverages Rust macros to simplify the process of writing Solana programs. #### [Prerequisites](https://solana.com/docs/intro/installation/dependencies#prerequisites-1) The default Anchor project test file (TypeScript) created with the `anchor init` command requires Node.js and Yarn. (The Rust test template is available using `anchor init --test-template rust`) ### Node Installation ### Yarn Installation #### [Installation](https://solana.com/docs/intro/installation/dependencies#installation) You can install the Anchor CLI and tooling in two ways: * Anchor Version Manager (AVM) — Recommended installation method * Without AVM — Install directly from GitHub AVMWithout AVM The Anchor Version Manager (AVM) allows you to install and manage different Anchor versions on your system and easily update Anchor versions in the future. To install Anchor using AVM, follow the steps below: 1. Install AVM with the following command: Terminal $ cargo install --git https://github.com/solana-foundation/anchor avm --force Copy 2. Confirm that AVM installed successfully: Terminal $ avm --version Copy 3. Install Anchor CLI using AVM: To install the latest version: Terminal $ avm install latest Copy $ avm use latest Copy To install a specific version, specify the version number: Terminal $ avm install 0.30.1 Copy $ avm use 0.30.1 Copy When installing the Anchor CLI on Linux or WSL, you may encounter this error: error: could not exec the linker cc = note: Permission denied (os error 13) If you see this error message, follow these steps: 1. Install the dependencies listed in the [Linux](https://solana.com/docs/intro/installation#install-dependencies) section at the top of this page. 2. Retry installing the Anchor CLI. 4. Verify that the installation succeeded, by checking the Anchor CLI version: Terminal $ anchor --version Copy You will see output like the following: anchor-cli 0.31.1 Don't forget to run the `avm use` command to declare the Anchor CLI version to run on your system. * If you installed the `latest` version, run `avm use latest`. * If you installed the version `0.30.1`, run `avm use 0.30.1`. ### [Install Surfpool CLI](https://solana.com/docs/intro/installation/dependencies#install-surfpool-cli) [Surfpool](https://surfpool.run/) is a tool for local development and an improved replacement for `solana-test-validator`. Learn more about Surfpool features in the [Surfpool documentation](https://docs.surfpool.run/) . 1. Install Surfpool with the following command: Terminal $ curl -sL https://run.surfpool.run/ | bash Copy 2. Verify that the installation was successful by checking the Surfpool CLI version: Terminal $ surfpool --version Copy You will see output like the following: surfpool 0.12.0 ### [Set up AI tooling for Solana development](https://solana.com/docs/intro/installation/dependencies#set-up-ai-tooling-for-solana-development) This section details optional AI tooling setup you can use to accelerate your Solana development. | Tool | Description | Link | | --- | --- | --- | | MCP | MCP server that you can connect to with cursor to improve Solana AI assisted development. | [https://mcp.solana.com/](https://mcp.solana.com/) | | LLMs.txt | LLM optimized documentation that you can use to train LLMs on Solana docs. | [https://solana.com/llms.txt](https://solana.com/llms.txt) | Is this page helpful? [Previous\ \ Quick Installation](https://solana.com/docs/intro/installation) [Next\ \ Solana CLI Basics](https://solana.com/docs/intro/installation/solana-cli-basics) ### Table of Contents [Prerequisites](https://solana.com/docs/intro/installation/dependencies#prerequisites) [Install Rust](https://solana.com/docs/intro/installation/dependencies#install-rust) [Install Solana CLI](https://solana.com/docs/intro/installation/dependencies#install-solana-cli) [Install Anchor CLI](https://solana.com/docs/intro/installation/dependencies#install-anchor-cli) [Prerequisites](https://solana.com/docs/intro/installation/dependencies#prerequisites-1) [Installation](https://solana.com/docs/intro/installation/dependencies#installation) [Install Surfpool CLI](https://solana.com/docs/intro/installation/dependencies#install-surfpool-cli) [Set up AI tooling for Solana development](https://solana.com/docs/intro/installation/dependencies#set-up-ai-tooling-for-solana-development) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/installation/dependencies.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Install the dependencies necessary to develop with Solana | Solana --- # SPL Token Basics | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [SPL Token Basics](https://solana.com/docs/tokens/basics) ========================================================== Copy MarkdownOpen This section covers the basics for interacting with SPL Tokens, focusing on the most commonly used instructions. All examples in this section work identically with both the original Token Program and the Token Extension Program (Token 2022), as they share the same base implementation. Refer to the [Metaplex documentation](https://developers.metaplex.com/token-metadata) for more information on how add metadata to SPL Tokens. The most common instructions you'll see when interacting with SPL Tokens include: [### Create a Token Mint\ \ Learn how to create an SPL Token mint.](https://solana.com/docs/tokens/basics/create-mint) [### Create a Token Account\ \ Learn how to create SPL Token Accounts.](https://solana.com/docs/tokens/basics/create-token-account) [### Mint Tokens\ \ Learn how to mint new units of a token.](https://solana.com/docs/tokens/basics/mint-tokens) [### Transfer Tokens\ \ Learn how to transfer tokens between token accounts.](https://solana.com/docs/tokens/basics/transfer-tokens) [### Approve Delegate\ \ Learn how to approve delegates for a token account.](https://solana.com/docs/tokens/basics/approve-delegate) [### Revoke Delegate\ \ Learn how to revoke the token account delegate.](https://solana.com/docs/tokens/basics/revoke-delegate) [### Set Authority\ \ Learn how to set authority for mints or token accounts.](https://solana.com/docs/tokens/basics/set-authority) [### Burn Tokens\ \ Learn how to burn tokens.](https://solana.com/docs/tokens/basics/burn-tokens) [### Sync Native\ \ Learn how to convert native SOL to wrapped SOL.](https://solana.com/docs/tokens/basics/sync-native) [### Close Token Account\ \ Learn how to close token accounts.](https://solana.com/docs/tokens/basics/close-account) [### Freeze Account\ \ Learn how to freeze token accounts.](https://solana.com/docs/tokens/basics/freeze-account) [### Thaw Account\ \ Learn how to thaw a frozen token account.](https://solana.com/docs/tokens/basics/thaw-account) Is this page helpful? [Previous\ \ Tokens on Solana](https://solana.com/docs/tokens) [Next\ \ Create a Token Mint](https://solana.com/docs/tokens/basics/create-mint) ### Table of Contents No Headings [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter SPL Token Basics | Solana --- # @solana/client | Solana [Solana Documentation](https://solana.com/docs) [Frontend](https://solana.com/docs/frontend) [@solana/client](https://solana.com/docs/frontend/client) ========================================================== Copy MarkdownOpen `@solana/client` keeps the runtime surface lean. One store, one RPC stack, and a wallet registry power the different helpers so the same instance can back CLIs, scripts, or full UIs. Actions, watchers, and helpers all share cache, subscriptions, and wallet sessions through that single client. When you are building a purely React experience it is usually faster to start with [`@solana/react-hooks`](https://solana.com/docs/frontend/react-hooks) . The hooks package wraps this same client runtime and exposes ready-made hooks so you only drop to the headless client when you need extra control. [Install](https://solana.com/docs/frontend/client#install) ----------------------------------------------------------- Terminal $ npm install @solana/client Copy Use any package manager; the client runs in browsers, workers, React, Svelte, or server-side runtimes. [Create a client once](https://solana.com/docs/frontend/client#create-a-client-once) ------------------------------------------------------------------------------------- Choose Wallet Standard connectors (auto discovery is the fastest way to start), then create the client. This single object exposes the store, actions, watchers, and helpers. import { autoDiscover, createClient } from "@solana/client"; const client \= createClient({ endpoint: "https://api.devnet.solana.com", websocketEndpoint: "wss://api.devnet.solana.com", walletConnectors: autoDiscover(), }); await client.actions.connectWallet("wallet-standard:phantom"); const balance \= await client.actions.fetchBalance("Fke...address"); console.log(balance.lamports?.toString()); The client store tracks cluster config, subscriptions, pending transactions, and wallet sessions. You can provide your own Zustand store if you need persistence or multi-tab coordination. [Wallet orchestration](https://solana.com/docs/frontend/client#wallet-orchestration) ------------------------------------------------------------------------------------- Connectors encapsulate Wallet Standard metadata plus connect/disconnect logic. Register the built-in `phantom()`, `solflare()`, `backpack()`, or `autoDiscover()` helpers, or wrap custom providers with `createWalletStandardConnector`. All wallet actions (connect, disconnect, sign, send) flow through the client registry so every consumer stays in sync. [Actions, watchers, and helpers](https://solana.com/docs/frontend/client#actions-watchers-and-helpers) ------------------------------------------------------------------------------------------------------- * **Actions** wrap common RPC reads and writes while updating the store (e.g., `fetchAccount`, `requestAirdrop`, `setCluster`). * **Watchers** multiplex websocket subscriptions, stream updates into the store, and give you abort handles for cleanup. * **Helpers** expose higher-level flows such as SOL transfers, SPL token helpers, signature polling, and transaction pools. const abortWatcher \= client.watchers.watchBalance( { address: "Fke...address" }, (lamports) \=> { console.log("live balance", lamports.toString()); }, ); // Later when the component unmounts or the flow ends abortWatcher.abort(); [Transaction helper pattern](https://solana.com/docs/frontend/client#transaction-helper-pattern) ------------------------------------------------------------------------------------------------- The transaction helper owns blockhash refresh, fee payer resolution, and signing. You can prepare, inspect, and send with whatever UX you prefer. const prepared \= await client.helpers.transaction.prepare({ authority: client.store.getState().wallet.session!, instructions: \[instructionA, instructionB\], }); await client.helpers.transaction.simulate(prepared, { commitment: "processed" }); const signature \= await client.helpers.transaction.send(prepared); console.log("submitted", signature.toString()); Use `prepareAndSend` for a pre-built flow (simulation plus logging) or call `sign` / `toWire` to collect signatures manually before relaying the wire format yourself. [Common patterns for Solana devs](https://solana.com/docs/frontend/client#common-patterns-for-solana-devs) ----------------------------------------------------------------------------------------------------------- * **Headless state machines**: Run the client inside API routes, scripts, or workers to reuse the same wallet + RPC orchestration logic that powers your UI. * **Realtime dashboards**: Combine watchers (balances, accounts, signatures) with your preferred UI library; the client handles websocket fan-out and cache invalidation. * **Custom stores**: Inject your own Zustand store to hydrate from IndexedDB/localStorage, mirror state to server sessions, or coordinate between browser tabs. * **Bridge to React hooks**: Pass a configured client instance to `@solana/react-hooks` when you want ergonomic hooks on top of the same runtime. * **Testability**: The single client interface can be mocked in unit tests, making it easy to simulate RPC responses or wallet sessions without a browser wallet present. Is this page helpful? [Previous\ \ Frontend](https://solana.com/docs/frontend) [Next\ \ @solana/react-hooks](https://solana.com/docs/frontend/react-hooks) ### Table of Contents [Install](https://solana.com/docs/frontend/client#install) [Create a client once](https://solana.com/docs/frontend/client#create-a-client-once) [Wallet orchestration](https://solana.com/docs/frontend/client#wallet-orchestration) [Actions, watchers, and helpers](https://solana.com/docs/frontend/client#actions-watchers-and-helpers) [Transaction helper pattern](https://solana.com/docs/frontend/client#transaction-helper-pattern) [Common patterns for Solana devs](https://solana.com/docs/frontend/client#common-patterns-for-solana-devs) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/frontend/client.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # JavaScript/TypeScript SDK for Solana | Solana [Solana Documentation](https://solana.com/docs) Solana SDKsOfficial SDKs [JavaScript/TypeScript SDK for Solana](https://solana.com/docs/clients/official/javascript) ============================================================================================ Copy MarkdownOpen [Solana Client](https://solana.com/docs/clients/official/javascript#solana-client) ----------------------------------------------------------------------------------- `@solana/client` is the headless Solana runtime that bundles RPC, wallets, transactions, and subscriptions in one store. | Package | Description | GitHub | | --- | --- | --- | | @solana/client | Headless client runtime | [Source](https://github.com/solana-foundation/framework-kit/tree/main/packages/client) | * [Guide: @solana/client overview](https://solana.com/docs/frontend/client) [Solana React Hooks](https://solana.com/docs/clients/official/javascript#solana-react-hooks) --------------------------------------------------------------------------------------------- `@solana/react-hooks` layers a React provider and hooks on top of `@solana/client`, reusing the same runtime and cache. | Package | Description | GitHub | | --- | --- | --- | | @solana/react-hooks | React provider + hooks for UIs | [Source](https://github.com/solana-foundation/framework-kit/tree/main/packages/react-hooks) | * [Guide: @solana/react-hooks](https://solana.com/docs/frontend/react-hooks) [Solana Kit](https://solana.com/docs/clients/official/javascript#solana-kit) ----------------------------------------------------------------------------- `@solana/kit` is the recommended TypeScript SDK for building on Solana. | Package | Description | GitHub | | --- | --- | --- | | @solana/kit | Core SDK | [Source](https://github.com/anza-xyz/kit) | | @solana-program/system | Interact with System program | [Source](https://github.com/solana-program/system/tree/main/clients/js) | | @solana-program/token | Interact with Token program | [Source](https://github.com/solana-program/token/tree/main/clients/js) | | @solana-program/token-2022 | Interact with Token-2022 program | [Source](https://github.com/solana-program/token-2022/tree/main/clients/js) | | @solana-program/memo | Interact with Memo program | [Source](https://github.com/solana-program/memo/tree/main/clients/js) | | @solana-program/compute-budget | Interact with Compute Budget program | [Source](https://github.com/solana-program/compute-budget/tree/main/clients/js) | * [Official Kit Documentation](https://www.solanakit.com/) * [Tutorial: Next.js + React Hooks](https://solana.com/docs/frontend/nextjs-solana) [Solana Web3.js](https://solana.com/docs/clients/official/javascript#solana-web3js) ------------------------------------------------------------------------------------ `@solana/web3.js` is the legacy TypeScript SDK for Solana. | Package | Description | GitHub | | --- | --- | --- | | @solana/web3.js | Core SDK | [Source](https://github.com/solana-foundation/solana-web3.js) | | @solana/spl-token | Interact with Token, Token-2022, and Associated Token programs | [Source](https://github.com/solana-program/token-2022/tree/main/clients/js-legacy) | | @solana/spl-memo | Interact with Memo program | [Source](https://github.com/solana-program/memo/tree/main/clients/js-legacy) | * [Example: Connect a wallet with Next.js](https://solana.com/developers/cookbook/wallets/connect-wallet-react) Is this page helpful? [Previous\ \ Rust SDK](https://solana.com/docs/clients/official/rust) [Next\ \ Python SDK](https://solana.com/docs/clients/community/python) ### Table of Contents [Solana Client](https://solana.com/docs/clients/official/javascript#solana-client) [Solana React Hooks](https://solana.com/docs/clients/official/javascript#solana-react-hooks) [Solana Kit](https://solana.com/docs/clients/official/javascript#solana-kit) [Solana Web3.js](https://solana.com/docs/clients/official/javascript#solana-web3js) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/clients/official/javascript.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Reading from Network | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Quick Start](https://solana.com/docs/intro/quick-start) [Reading from Network](https://solana.com/docs/intro/quick-start/reading-from-network) ======================================================================================= Copy MarkdownOpen Read data from the Solana network by fetching different accounts. This section will help you understand the structure of Solana [accounts](https://solana.com/docs/core/accounts) . Each Solana account has a unique [address](https://solana.com/docs/core/accounts#account-address) that is used to locate its corresponding on-chain data. Accounts contain either [state data or an executable program](https://solana.com/docs/core/accounts#types-of-accounts) . [Fetch a wallet account](https://solana.com/docs/intro/quick-start/reading-from-network#fetch-a-wallet-account) ---------------------------------------------------------------------------------------------------------------- A wallet is an account owned by the [System Program](https://solana.com/docs/core/programs#the-system-program) . Wallets are primarily used to hold SOL and sign transactions. When SOL is sent to a new address for the first time, a system account is automatically created. The example below generates a new keypair, requests SOL to fund the new public key address, and retrieves the account data for the newly funded wallet. Fetch account import { Keypair, Connection, LAMPORTS\_PER\_SOL } from "@solana/web3.js"; const keypair \= Keypair.generate(); console.log(\`Public Key: ${keypair.publicKey}\`); const connection \= new Connection("http://localhost:8899", "confirmed"); // Funding an address with SOL automatically creates an account const signature \= await connection.requestAirdrop( keypair.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); const accountInfo \= await connection.getAccountInfo(keypair.publicKey); console.log(JSON.stringify(accountInfo, null, 2)); Console RunClick to execute the code. Fetch account import { Keypair, Connection, LAMPORTS\_PER\_SOL } from "@solana/web3.js"; const keypair \= Keypair.generate(); console.log(\`Public Key: ${keypair.publicKey}\`); const connection \= new Connection("http://localhost:8899", "confirmed"); // Funding an address with SOL automatically creates an account const signature \= await connection.requestAirdrop( keypair.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); const accountInfo \= await connection.getAccountInfo(keypair.publicKey); console.log(JSON.stringify(accountInfo, null, 2)); Console RunClick to execute the code. When you fetch a wallet account, the response includes the fields shown in the example output on the right. Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } The `data` field contains the account's data stored as bytes. For wallet accounts, this field is empty (0 bytes). Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } The `executable` field indicates whether the account's `data` field contains executable program code. For wallet accounts this field is `false`. Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } The `lamports` field contains the account's SOL balance, in [lamports](https://solana.com/docs/references/terminology#lamport) . Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } The `owner` field shows the program that owns the account. For wallets, the owner is always the System Program, with the address `11111111111111111111111111111111`. Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } The `rentEpoch` field is a legacy field from a deprecated rent mechanism. (This field is included for backward compatibility.) Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } The `space` field shows the number of bytes contained in the `data` field. This is not a field in the [Account type](https://solana.com/docs/core/accounts#account-structure) itself, but is included in the response. In this example, the `space` field is 0 because the `data` field contains 0 bytes of data. Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } When you fetch a wallet account, the response includes the fields shown in the example output on the right. The `data` field contains the account's data stored as bytes. For wallet accounts, this field is empty (0 bytes). The `executable` field indicates whether the account's `data` field contains executable program code. For wallet accounts this field is `false`. The `lamports` field contains the account's SOL balance, in [lamports](https://solana.com/docs/references/terminology#lamport) . The `owner` field shows the program that owns the account. For wallets, the owner is always the System Program, with the address `11111111111111111111111111111111`. The `rentEpoch` field is a legacy field from a deprecated rent mechanism. (This field is included for backward compatibility.) The `space` field shows the number of bytes contained in the `data` field. This is not a field in the [Account type](https://solana.com/docs/core/accounts#account-structure) itself, but is included in the response. In this example, the `space` field is 0 because the `data` field contains 0 bytes of data. Example output { "data": { "type": "Buffer", "data": \[\] }, "executable": false, "lamports": 1000000000, "owner": "11111111111111111111111111111111", "rentEpoch": 0, "space": 0 } [Fetch the Token Program](https://solana.com/docs/intro/quick-start/reading-from-network#fetch-the-token-program) ------------------------------------------------------------------------------------------------------------------ The example below fetches the Token Program to demonstrate the difference between wallet and program accounts. The program account stores the compiled bytecode for the Token Program's [source code](https://github.com/solana-program/token/tree/main/program) . You can view this program account on the [Solana Explorer](https://explorer.solana.com/address/TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA) . Fetch program account import { Connection, PublicKey } from "@solana/web3.js"; const connection \= new Connection( "https://api.mainnet.solana.com", "confirmed" ); const address \= new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); const accountInfo \= await connection.getAccountInfo(address); console.log( Console RunClick to execute the code. Fetch program account import { Connection, PublicKey } from "@solana/web3.js"; const connection \= new Connection( "https://api.mainnet.solana.com", "confirmed" ); const address \= new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); const accountInfo \= await connection.getAccountInfo(address); console.log( Console RunClick to execute the code. The Token Program is an executable program account. Programs have the same underlying fields as all [accounts](https://solana.com/docs/core/accounts#account-structure) , but with key differences. Token program account { "data": { "type": "Buffer", "data": \[127, "...truncated, total bytes: 134080...", 0\] }, "executable": true, "lamports": 4522329612, "owner": "BPFLoader2111111111111111111111111111111111", "rentEpoch": 18446744073709552000, "space": 134080 } The `executable` field is set to `true`, which indicates that the account's `data` field contains executable code. Token program account { "data": { "type": "Buffer", "data": \[127, "...truncated, total bytes: 134080...", 0\] }, "executable": true, "lamports": 4522329612, "owner": "BPFLoader2111111111111111111111111111111111", "rentEpoch": 18446744073709552000, "space": 134080 } The `data` field stores the program's executable code. Token program account { "data": { "type": "Buffer", "data": \[127, "...truncated, total bytes: 134080...", 0\] }, "executable": true, "lamports": 4522329612, "owner": "BPFLoader2111111111111111111111111111111111", "rentEpoch": 18446744073709552000, "space": 134080 } Every program account is owned by its [loader program](https://solana.com/docs/core/programs#loader-programs) . In this example, the `owner` is the BPFLoader2 program. Token program account { "data": { "type": "Buffer", "data": \[127, "...truncated, total bytes: 134080...", 0\] }, "executable": true, "lamports": 4522329612, "owner": "BPFLoader2111111111111111111111111111111111", "rentEpoch": 18446744073709552000, "space": 134080 } The Token Program is an executable program account. Programs have the same underlying fields as all [accounts](https://solana.com/docs/core/accounts#account-structure) , but with key differences. The `executable` field is set to `true`, which indicates that the account's `data` field contains executable code. The `data` field stores the program's executable code. Every program account is owned by its [loader program](https://solana.com/docs/core/programs#loader-programs) . In this example, the `owner` is the BPFLoader2 program. Token program account { "data": { "type": "Buffer", "data": \[127, "...truncated, total bytes: 134080...", 0\] }, "executable": true, "lamports": 4522329612, "owner": "BPFLoader2111111111111111111111111111111111", "rentEpoch": 18446744073709552000, "space": 134080 } [Fetch a mint account](https://solana.com/docs/intro/quick-start/reading-from-network#fetch-a-mint-account) ------------------------------------------------------------------------------------------------------------ A [mint account](https://github.com/solana-program/token/blob/program%40v8.0.0/program/src/state.rs#L16-L30) is an account owned by the Token Program that stores global metadata for a specific token. This includes the total supply, number of decimals, and the accounts that are authorized to mint or freeze tokens. The mint account's address uniquely identifies a token on the Solana network. The example below fetches the USD Coin Mint account to demonstrate how a program's state is stored in a separate account. Fetch program account import { Connection, PublicKey } from "@solana/web3.js"; const connection \= new Connection( "https://api.mainnet.solana.com", "confirmed" ); const address \= new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const accountInfo \= await connection.getAccountInfo(address); console.log( Console RunClick to execute the code. Fetch program account import { Connection, PublicKey } from "@solana/web3.js"; const connection \= new Connection( "https://api.mainnet.solana.com", "confirmed" ); const address \= new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const accountInfo \= await connection.getAccountInfo(address); console.log( Console RunClick to execute the code. Mint accounts store state, not executable code. They are owned by the Token Program, which includes instructions defining how to create and update mint accounts. Mint account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } The mint account's `data` field stores state, not executable code, so the `executable` field is `false`. The Token Program defines the `Mint` data type, which is stored in the `data` field. Mint account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } The `data` field contains the serialized `Mint` account state, such as the mint authority, total supply, number of decimals. To read from a Mint account, you must deserialize the `data` field into the `Mint` data type, which is shown in the [next example](https://solana.com/docs/intro/quick-start/reading-from-network#deserialize-mint-account) . Mint account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } The mint account is owned by the [Token Program](https://solana.com/docs/references/terminology#token-program) . This means that its `data` field can only be modified by the Token Program' instructions. Mint Account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } Mint accounts store state, not executable code. They are owned by the Token Program, which includes instructions defining how to create and update mint accounts. The mint account's `data` field stores state, not executable code, so the `executable` field is `false`. The Token Program defines the `Mint` data type, which is stored in the `data` field. The `data` field contains the serialized `Mint` account state, such as the mint authority, total supply, number of decimals. To read from a Mint account, you must deserialize the `data` field into the `Mint` data type, which is shown in the [next example](https://solana.com/docs/intro/quick-start/reading-from-network#deserialize-mint-account) . The mint account is owned by the [Token Program](https://solana.com/docs/references/terminology#token-program) . This means that its `data` field can only be modified by the Token Program' instructions. Mint account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } [Deserialize mint account](https://solana.com/docs/intro/quick-start/reading-from-network#deserialize-mint-account) -------------------------------------------------------------------------------------------------------------------- Before the raw bytes in an account's `data` field can be interpreted meaningfully they must be deserialized. The appropriate data type is defined by the program that owns the account. Most Solana programs provide client libraries with helper functions that abstract away the deserialization process. These functions convert the raw account bytes into structured data types, making it easier to work with the account data. For example, the `@solana/spl-token` library includes the `getMint()` function to help deserialize a mint account's `data` field into the [Mint](https://github.com/solana-program/token/blob/program%40v8.0.0/program/src/state.rs#L16-L30) data type defined by the Token Program. Deserialize mint account data import { PublicKey, Connection } from "@solana/web3.js"; import { getMint } from "@solana/spl-token"; const connection \= new Connection( "https://api.mainnet.solana.com", "confirmed" ); const address \= new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const mintData \= await getMint(connection, address, "confirmed"); console.log( Console RunClick to execute the code. Deserialize mint account data import { PublicKey, Connection } from "@solana/web3.js"; import { getMint } from "@solana/spl-token"; const connection \= new Connection( "https://api.mainnet.solana.com", "confirmed" ); const address \= new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); const mintData \= await getMint(connection, address, "confirmed"); console.log( Console RunClick to execute the code. Mint account type pub struct Mint { /// Optional authority used to mint new tokens. The mint authority may only /// be provided during mint creation. If no mint authority is present /// then the mint has a fixed supply and no further tokens may be /// minted. pub mint\_authority: COption, /// Total supply of tokens. pub supply: u64, /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, /// Is \`true\` if this structure has been initialized pub is\_initialized: bool, /// Optional authority to freeze token accounts. pub freeze\_authority: COption, } The `getMint()` function deserializes a mint account's `data` field into the Mint account type. Mint account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } You can view the fully deserialized [mint account](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v?cluster=mainnet-beta) data on the Solana Explorer. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `address` field contains the mint account's address. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `mintAuthority` field shows the only account that can create new units of the token. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `supply` field shows the total number of tokens that have been minted. This value is measured in the smallest unit of the token. To get the total supply in standard units, adjust the value of the `supply` field by the `decimals`. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `decimals` field shows the number of decimal places for the token. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `isInitialized` field indicates whether the mint account has been initialized. This field is a security check used in the Token Program. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `freezeAuthority` field shows the account with authority to freeze token accounts. A frozen token account cannot transfer or burn the token it contains. Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `tlvData` field contains extra data for Token Extensions and requires further deserialization. This field is only relevant to accounts created by the [Token Extension Program](https://solana.com/docs/tokens/extensions) (Token2022). Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } The `getMint()` function deserializes a mint account's `data` field into the Mint account type. Mint account { "data": { "type": "Buffer", "data": \[1, "...truncated, total bytes: 82...", 103\] }, "executable": false, "lamports": 407438077149, "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "rentEpoch": 18446744073709552000, "space": 82 } You can view the fully deserialized [mint account](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v?cluster=mainnet-beta) data on the Solana Explorer. The `address` field contains the mint account's address. The `mintAuthority` field shows the only account that can create new units of the token. The `supply` field shows the total number of tokens that have been minted. This value is measured in the smallest unit of the token. To get the total supply in standard units, adjust the value of the `supply` field by the `decimals`. The `decimals` field shows the number of decimal places for the token. The `isInitialized` field indicates whether the mint account has been initialized. This field is a security check used in the Token Program. The `freezeAuthority` field shows the account with authority to freeze token accounts. A frozen token account cannot transfer or burn the token it contains. The `tlvData` field contains extra data for Token Extensions and requires further deserialization. This field is only relevant to accounts created by the [Token Extension Program](https://solana.com/docs/tokens/extensions) (Token2022). Deserialized mint data { "address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "mintAuthority": "BJE5MMbqXjVwjAF7oxwPYXnTXDyspzZyt4vwenNw5ruG", "supply": "8985397351591790", "decimals": 6, "isInitialized": true, "freezeAuthority": "7dGbd2QZcCKcTndnHcTL8q7SMVXAkp688NTQYwrRCrar", "tlvData": { "type": "Buffer", "data": \[\] } } Is this page helpful? [Previous\ \ Quick Start](https://solana.com/docs/intro/quick-start) [Next\ \ Writing to the Network](https://solana.com/docs/intro/quick-start/writing-to-network) ### Table of Contents [Fetch a wallet account](https://solana.com/docs/intro/quick-start/reading-from-network#fetch-a-wallet-account) [Fetch the Token Program](https://solana.com/docs/intro/quick-start/reading-from-network#fetch-the-token-program) [Fetch a mint account](https://solana.com/docs/intro/quick-start/reading-from-network#fetch-a-mint-account) [Deserialize mint account](https://solana.com/docs/intro/quick-start/reading-from-network#deserialize-mint-account) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/quick-start/reading-from-network.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Solana RPC HTTP Methods | Solana [Solana Documentation](https://solana.com/docs) [Solana RPC Methods](https://solana.com/docs/rpc) [Solana RPC HTTP Methods](https://solana.com/docs/rpc/http) ============================================================ Copy MarkdownOpen Solana nodes accept HTTP requests using the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification. > For JavaScript applications, use the [@solana/web3.js](https://github.com/solana-labs/solana-web3.js) > library as a convenient interface for the RPC methods to interact with a Solana node. For an PubSub connection to a Solana node, use the [Websocket API](https://solana.com/docs/rpc/websocket/) > . [RPC HTTP Endpoint](https://solana.com/docs/rpc/http#rpc-http-endpoint) ------------------------------------------------------------------------ Default port: `8899` * [http://localhost:8899](http://localhost:8899/) * [http://192.168.1.88:8899](http://192.168.1.88:8899/) [Request Formatting](https://solana.com/docs/rpc/http#request-formatting) -------------------------------------------------------------------------- To make a JSON-RPC request, send an HTTP POST request with a `Content-Type: application/json` header. The JSON request data should contain 4 fields: * `jsonrpc: ` - set to `"2.0"` * `id: ` - a unique identifier for the request, generated by the client. Typically a string or number, though null is technically allowed but not advised * `method: ` - a string containing the method to be invoked * `params: ` - a JSON array of ordered parameter values Example using curl: curl https://api.devnet.solana.com \-s -X POST \-H "Content-Type: application/json" \-d ' { "jsonrpc": "2.0", "id": 1, "method": "getBalance", "params": \[\ \ "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri"\ \ \] } ' The response output will be a JSON object with the following fields: * `jsonrpc: ` - matching the request specification * `id: ` - matching the request identifier * `result: ` - requested data or success confirmation Requests can be sent in batches by sending an array of JSON-RPC request objects as the data for a single POST. ### [Example Request](https://solana.com/docs/rpc/http#example-request) The commitment parameter should be included as the last element in the `params` array: curl https://api.devnet.solana.com \-s -X POST \-H "Content-Type: application/json" \-d ' { "jsonrpc": "2.0", "id": 1, "method": "getBalance", "params": \[\ \ "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",\ \ {\ \ "commitment": "finalized"\ \ }\ \ \] } ' [Definitions](https://solana.com/docs/rpc/http#definitions) ------------------------------------------------------------ * Hash: A SHA-256 hash of a chunk of data. * Pubkey: The public key of a Ed25519 key-pair. * Transaction: A list of Solana instructions signed by a client keypair to authorize those actions. * Signature: An Ed25519 signature of transaction's payload data including instructions. This can be used to identify transactions. [Health Check](https://solana.com/docs/rpc/http#health-check) -------------------------------------------------------------- Although not a JSON RPC API, a `GET /health` at the RPC HTTP Endpoint provides a health-check mechanism for use by load balancers or other network infrastructure. This request will always return a HTTP 200 OK response with a body of "ok", "behind" or "unknown": * `ok`: The node is within `HEALTH_CHECK_SLOT_DISTANCE` slots from the latest cluster confirmed slot * `behind { distance }`: The node is behind `distance` slots from the latest cluster confirmed slot where `distance > HEALTH_CHECK_SLOT_DISTANCE` * `unknown`: The node is unable to determine where it stands in relation to the cluster Is this page helpful? [Previous\ \ Data Structures as JSON](https://solana.com/docs/rpc/json-structures) [Next\ \ getAccountInfo](https://solana.com/docs/rpc/http/getaccountinfo) ### Table of Contents [RPC HTTP Endpoint](https://solana.com/docs/rpc/http#rpc-http-endpoint) [Request Formatting](https://solana.com/docs/rpc/http#request-formatting) [Example Request](https://solana.com/docs/rpc/http#example-request) [Definitions](https://solana.com/docs/rpc/http#definitions) [Health Check](https://solana.com/docs/rpc/http#health-check) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/rpc/http/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Solana RPC HTTP Methods | Solana --- # Interacting with Solana | Solana [Payments](https://solana.com/docs) [Interacting with Solana](https://solana.com/docs/payments/interacting-with-solana) ==================================================================================== Copy MarkdownOpen Before building payment flows, you need to connect to Solana and understand how to query network data. This guide covers the basics: establishing a connection and using the RPC methods you'll need for payments using the [@solana/kit](https://www.npmjs.com/package/@solana/kit) TypeScript SDK and [Solana CLI](https://solana.com/docs/intro/installation) . Additionally, we will cover the basics of using the [Solana Explorer](https://explorer.solana.com/) to manually verify payments, inspect accounts, and debug issues. [Connecting to Solana](https://solana.com/docs/payments/interacting-with-solana#connecting-to-solana) ------------------------------------------------------------------------------------------------------ Solana's RPC API is the primary way to programmatically interact with the network. Your RPC URL is effectively an API key to the network. Do not use public RPC for production The public endpoints (`api.mainnet-beta.solana.com`, `api.devnet.solana.com`) are rate-limited, have no SLA, and are unsuitable for production payment flows. Use an [RPC provider](https://solana.com/rpc) to secure a private RPC endpoint for production deployments. For development and testing, you can use rate-limited public endpoints. Create an RPC client to interact with the network: Kit CLI import { createSolanaRpc, createSolanaRpcSubscriptions } from "@solana/kit"; const rpc \= createSolanaRpc("https://api.mainnet-beta.solana.com"); const rpcSubscriptions \= createSolanaRpcSubscriptions( "wss://api.mainnet-beta.solana.com" ); For development, use devnet (`https://api.devnet.solana.com`) or a local validator like [Surfpool](https://solana.com/docs/intro/installation/surfpool-cli-basics) . [Common RPC Methods](https://solana.com/docs/payments/interacting-with-solana#common-rpc-methods) -------------------------------------------------------------------------------------------------- Solana's [JSON-RPC API](https://solana.com/docs/rpc) exposes methods to query the network. Here are the ones you'll use most for payment flows. ### [Getting Account Info](https://solana.com/docs/payments/interacting-with-solana#getting-account-info) All accounts on Solana are addressable by their public key. Use the [`getAccountInfo`](https://solana.com/docs/rpc/http/getaccountinfo) RPC method to fetch information about any account. The `getAccountInfo` method returns an `AccountInfo` object, which contains the account's public key, SOL balance, data, and some other metadata. The `data` field is a base64 encoded string of the account's data. You can encode it to bytes using the `getBase64Codec` method from the `@solana/kit` package and then decode it to a readable object using the expected codec (if known) for the account's data (e.g., `getTokenCodec` for token accounts). Kit CLI const accountInfo \= await rpc .getAccountInfo(address("7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV"), { encoding: "base64" }) .send(); const dataBytes \= getBase64Codec().encode(accountInfo.value.data); const parsedTokenData \= getTokenCodec().decode(dataBytes); console.log(parsedTokenData); ### [Getting Token Balances](https://solana.com/docs/payments/interacting-with-solana#getting-token-balances) Check a token account's balance using the [`getTokenAccountBalance`](https://solana.com/docs/rpc/http/gettokenaccountbalance) RPC method: Kit CLI const balance \= await rpc.getTokenAccountBalance(tokenAccountAddress).send(); console.log(balance.value.uiAmount); // Human-readable (e.g., 100.50) console.log(balance.value.amount); // Base units (e.g., "100500000") ### [Building Transactions](https://solana.com/docs/payments/interacting-with-solana#building-transactions) Every transaction needs a recent blockhash to ensure it is valid (and not stale). Fetch one before creating a payment transaction using the [`getLatestBlockhash`](https://solana.com/docs/rpc/http/getlatestblockhash) RPC method: Kit CLI const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); > Blockhashes expire after ~60 seconds. Fetch a fresh one immediately before signing and sending. ### [Checking Transaction Status](https://solana.com/docs/payments/interacting-with-solana#checking-transaction-status) Verify a transaction settled using the [`getSignatureStatuses`](https://solana.com/docs/rpc/http/getsignaturestatuses) RPC method: Kit CLI const status \= await rpc.getSignatureStatuses(\[signature\]).send(); const result \= status.value\[0\]; // result.confirmationStatus: "processed" | "confirmed" | "finalized" ### [Getting Transaction Details](https://solana.com/docs/payments/interacting-with-solana#getting-transaction-details) Fetch the full details of a confirmed transaction using the [`getTransaction`](https://solana.com/docs/rpc/http/gettransaction) RPC method: Kit CLI const transaction \= await rpc .getTransaction(signature, { maxSupportedTransactionVersion: 0 }) .send(); ### [Transaction History](https://solana.com/docs/payments/interacting-with-solana#transaction-history) Get recent transactions for an address using the [`getSignaturesForAddress`](https://solana.com/docs/rpc/http/getsignaturesforaddress) RPC method: Kit CLI const signatures \= await rpc .getSignaturesForAddress(walletAddress, { limit: 10 }) .send(); > For comprehensive payment monitoring, see [Accept Payments](https://solana.com/docs/payments/accept-payments) > which covers webhooks and real-time transaction detection. [Exploring Public Data](https://solana.com/docs/payments/interacting-with-solana#exploring-public-data) -------------------------------------------------------------------------------------------------------- Solana's public ledger means every transaction, token account, and mint is fully auditable. Block explorers let you manually verify payments, inspect accounts, and debug issues without writing code. **What you can look up:** * Verify a payment settled * Inspect token account balances * Debug failed transactions * Look up mint details (supply, decimals, authority) **Common explorers:** [Solana Explorer](https://explorer.solana.com/) , [SolanaFM](https://solana.fm/) , [Solscan](https://solscan.io/) , [Orb](https://www.orbmarkets.io/) **Example links:** * [USDC Token Mint](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) — Supply, markets, holders, and transactions for USDC * [USDC Token Transfer](https://explorer.solana.com/tx/3d2mQChCbqM5iogAN5PZw7KGZuVtQq3LbwU8hk55u4iUvYH1XJ7SQVQpWwoZj43MtthBqGBoqGBe9fn4Bo1VznjG) — Details of a USDC payment transaction * [USDG Token Account](https://explorer.solana.com/address/7v45FoihixmfocS3LbANUrEGZQKEJ7QQUg8K9jtZd3St) — A user's USDG balance and transaction history Is this page helpful? [Previous\ \ How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) [Next\ \ Send Payments](https://solana.com/docs/payments/send-payments) ### Table of Contents [Connecting to Solana](https://solana.com/docs/payments/interacting-with-solana#connecting-to-solana) [Common RPC Methods](https://solana.com/docs/payments/interacting-with-solana#common-rpc-methods) [Getting Account Info](https://solana.com/docs/payments/interacting-with-solana#getting-account-info) [Getting Token Balances](https://solana.com/docs/payments/interacting-with-solana#getting-token-balances) [Building Transactions](https://solana.com/docs/payments/interacting-with-solana#building-transactions) [Checking Transaction Status](https://solana.com/docs/payments/interacting-with-solana#checking-transaction-status) [Getting Transaction Details](https://solana.com/docs/payments/interacting-with-solana#getting-transaction-details) [Transaction History](https://solana.com/docs/payments/interacting-with-solana#transaction-history) [Exploring Public Data](https://solana.com/docs/payments/interacting-with-solana#exploring-public-data) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/interacting-with-solana.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Interacting with Solana | Solana --- # Introductory commands for getting started on the Solana CLI | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Installation](https://solana.com/docs/intro/installation) [Solana CLI Basics](https://solana.com/docs/intro/installation/solana-cli-basics) ================================================================================== Copy MarkdownOpen This section provides some common commands and examples to help you get you started using the Solana CLI. [Solana config](https://solana.com/docs/intro/installation/solana-cli-basics#solana-config) -------------------------------------------------------------------------------------------- Your Solana config specifies the following variables: * **Config file**: The path to your config file * **RPC URL & Websocket URL**: The Solana cluster to which the CLI makes requests * **Keypair path**: The path to the default Solana wallet (keypair) used to pay transaction fees and deploy programs. By default, this file is stored at `~/.config/solana/id.json`. To see your current configuration settings, enter the follow command in your terminal. Terminal $ solana config get Copy A successful command will return output similar to the following: Example output Config File: /Users/test/.config/solana/cli/config.yml RPC URL: https://api.mainnet-beta.solana.com WebSocket URL: wss://api.mainnet-beta.solana.com/ (computed) Keypair Path: /Users/test/.config/solana/id.json Commitment: confirmed You can change the Solana CLI cluster with the following commands: Full commandsShort commands Terminal $ solana config set --url mainnet-beta Copy $ solana config set --url devnet Copy $ solana config set --url localhost Copy $ solana config set --url testnet Copy [Create a wallet](https://solana.com/docs/intro/installation/solana-cli-basics#create-a-wallet) ------------------------------------------------------------------------------------------------ Before you can send a transactions using the Solana CLI, you need a Solana wallet funded with SOL. To generate a keypair at the default keypair path, run the following command: Terminal $ solana-keygen new Copy A successful command will return output similar to the following: Example output Generating a new keypair For added security, enter a BIP39 passphrase NOTE! This passphrase improves security of the recovery seed phrase NOT the keypair file itself, which is stored as insecure plain text BIP39 Passphrase (empty for none): Wrote new keypair to /Users/test/.config/solana/id.json \=========================================================================== pubkey: 8dBTPrjnkXyuQK3KDt9wrZBfizEZijmmUQXVHpFbVwGT \=========================================================================== Save this seed phrase and your BIP39 passphrase to recover your new keypair: cream bleak tortoise ocean nasty game gift forget fancy salon mimic amazing \=========================================================================== This command will not override an existing account at the default location, unless you use the `--force` flag. To view your wallet's address (public key), run: Terminal $ solana address Copy [Airdrop SOL](https://solana.com/docs/intro/installation/solana-cli-basics#airdrop-sol) ---------------------------------------------------------------------------------------- Request an airdrop of SOL to your wallet to pay for transactions and program deployments. 1. Set your cluster to Devnet: Terminal $ solana config set -ud Copy 2. Request an airdrop of Devnet SOL: Terminal $ solana airdrop 2 Copy Devnet airdrops limit requests to 5 SOL per request. If you hit rate limits or encounter errors, try using the [Web Faucet](https://faucet.solana.com/) instead. To check your wallet's SOL balance, run the following command: Terminal $ solana balance Copy Is this page helpful? [Previous\ \ Install Dependencies](https://solana.com/docs/intro/installation/dependencies) [Next\ \ Anchor CLI Basics](https://solana.com/docs/intro/installation/anchor-cli-basics) ### Table of Contents [Solana config](https://solana.com/docs/intro/installation/solana-cli-basics#solana-config) [Create a wallet](https://solana.com/docs/intro/installation/solana-cli-basics#create-a-wallet) [Airdrop SOL](https://solana.com/docs/intro/installation/solana-cli-basics#airdrop-sol) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/installation/solana-cli-basics.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Introductory commands for getting started on the Solana CLI | Solana --- # Extensions | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Extensions](https://solana.com/docs/tokens/extensions) ======================================================== Copy MarkdownOpen [What are Token Extensions?](https://solana.com/docs/tokens/extensions#what-are-token-extensions) -------------------------------------------------------------------------------------------------- The Token Extensions Program (Token 2022) provides more features through extra instructions referred to as extensions. Extensions are optional features you can add to a token mint or token account. You can find the implementation of these extension instructions in the Token Extensions Program [source code](https://github.com/solana-program/token-2022/tree/main/program/src/extension) . Each extension adds specific state that's generally initialized during mint or token account creation. When initializing either account, you can enable specific extensions simultaneously for different functionality. Most extensions can't be added after an account is initialized. This is an important consideration when designing your token, as you'll need to plan ahead for which features you want your token to support. Integration guides for each extension are available in the [Token Extensions developer documentation](https://solana.com/developers/guides/token-extensions/getting-started) . Some extensions are incompatible with each other and you can't enable them simultaneously on the same token mint or token account. For example, you can't combine the `NonTransferable` extension with the `TransferFeeConfig` extension, since they have conflicting behaviors. The Token Extensions Program defines an [`ExtensionType`](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/extension/mod.rs#L1059) enum that lists all available extensions you can add to a token mint or token account. Each variant represents a different extension with unique functionality. The `ExtensionType` enum is defined as follows: Token Extensions /// Extensions that can be applied to mints or accounts. Mint extensions must /// only be applied to mint accounts, and account extensions must only be /// applied to token holding accounts. #\[repr(u16)\] #\[cfg\_attr(feature \= "serde-traits", derive(Serialize, Deserialize))\] #\[cfg\_attr(feature \= "serde-traits", serde(rename\_all \= "camelCase"))\] #\[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)\] pub enum ExtensionType { /// Used as padding if the account size would otherwise be 355, same as a /// multisig Uninitialized, /// Includes transfer fee rate info and accompanying authorities to withdraw /// and set the fee TransferFeeConfig, /// Includes withheld transfer fees TransferFeeAmount, /// Includes an optional mint close authority MintCloseAuthority, /// Auditor configuration for confidential transfers ConfidentialTransferMint, /// State for confidential transfers ConfidentialTransferAccount, /// Specifies the default Account::state for new Accounts DefaultAccountState, /// Indicates that the Account owner authority cannot be changed ImmutableOwner, /// Require inbound transfers to have memo MemoTransfer, /// Indicates that the tokens from this mint can't be transferred NonTransferable, /// Tokens accrue interest over time, InterestBearingConfig, /// Locks privileged token operations from happening via CPI CpiGuard, /// Includes an optional permanent delegate PermanentDelegate, /// Indicates that the tokens in this account belong to a non-transferable /// mint NonTransferableAccount, /// Mint requires a CPI to a program implementing the "transfer hook" /// interface TransferHook, /// Indicates that the tokens in this account belong to a mint with a /// transfer hook TransferHookAccount, /// Includes encrypted withheld fees and the encryption public that they are /// encrypted under ConfidentialTransferFeeConfig, /// Includes confidential withheld transfer fees ConfidentialTransferFeeAmount, /// Mint contains a pointer to another account (or the same account) that /// holds metadata MetadataPointer, /// Mint contains token-metadata TokenMetadata, /// Mint contains a pointer to another account (or the same account) that /// holds group configurations GroupPointer, /// Mint contains token group configurations TokenGroup, /// Mint contains a pointer to another account (or the same account) that /// holds group member configurations GroupMemberPointer, /// Mint contains token group member configurations TokenGroupMember, /// Mint allowing the minting and burning of confidential tokens ConfidentialMintBurn, /// Tokens whose UI amount is scaled by a given amount ScaledUiAmount, /// Tokens where minting / burning / transferring can be paused Pausable, /// Indicates that the account belongs to a pausable mint PausableAccount, /// Test variable-length mint extension #\[cfg(test)\] VariableLenMintTest \= u16::MAX \- 2, /// Padding extension used to make an account exactly Multisig::LEN, used /// for testing #\[cfg(test)\] AccountPaddingTest, /// Padding extension used to make a mint exactly Multisig::LEN, used for /// testing #\[cfg(test)\] MintPaddingTest, } Each extension adds specialized functionality by including extra state to a mint or token account. All extension specific state is stored in the [`tlv_data`](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/extension/mod.rs#L546) field, which follows the base account data type. You must further deserialize the `tlv_data` (containing extension state) according to the specific extension types enabled for that account. Token Extensions /// Encapsulates immutable base state data (mint or account) with possible /// extensions, where the base state is Pod for zero-copy serde. #\[derive(Debug, PartialEq)\] pub struct PodStateWithExtensions<'data, S: BaseState + Pod\> { /// Unpacked base data pub base: &'data S, /// Slice of data containing all TLV data, deserialized on demand tlv\_data: &'data \[u8\], } Is this page helpful? [Previous\ \ Thaw Account](https://solana.com/docs/tokens/basics/thaw-account) [Next\ \ Scaled UI Amount](https://solana.com/docs/tokens/extensions/scaled-ui-amount) ### Table of Contents [What are Token Extensions?](https://solana.com/docs/tokens/extensions#what-are-token-extensions) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/extensions/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Extensions | Solana --- # Writing to the Network | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Quick Start](https://solana.com/docs/intro/quick-start) [Writing to the Network](https://solana.com/docs/intro/quick-start/writing-to-network) ======================================================================================= Copy MarkdownOpen In the previous section, you learned how to read data from the Solana network. Now you'll learn how to write data to it. Writing to the Solana network involves sending transactions that contain one or more instruction. Programs define the business logic for what each [instruction](https://solana.com/docs/core/instructions) does. When you submit a [transaction](https://solana.com/docs/core/transactions) , the Solana runtime executes each instruction in sequence and atomically. The examples in this section show how to build and send transactions to invoke Solana programs, they include: 1. Transferring SOL between accounts 2. Creating a new token [Transfer SOL](https://solana.com/docs/intro/quick-start/writing-to-network#transfer-sol) ------------------------------------------------------------------------------------------ The example below transfers SOL between two accounts. Each account has an owner program, which is the only program that can deduct the account's SOL balance. All wallet accounts are owned by the System Program. To transfer SOL, you must invoke the System Program's [transfer](https://github.com/anza-xyz/agave/blob/v2.1.11/programs/system/src/system_processor.rs#L183-L213) instruction. Transfer SOL import { LAMPORTS\_PER\_SOL, SystemProgram, Transaction, sendAndConfirmTransaction, Keypair, Connection } from "@solana/web3.js"; const connection \= new Connection("http://localhost:8899", "confirmed"); const sender \= new Keypair(); const receiver \= new Keypair(); const signature \= await connection.requestAirdrop( sender.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); const transferInstruction \= SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: receiver.publicKey, lamports: 0.01 \* LAMPORTS\_PER\_SOL }); const transaction \= new Transaction().add(transferInstruction); const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[sender\] ); console.log("Transaction Signature:", \`${transactionSignature}\`); const senderBalance \= await connection.getBalance(sender.publicKey); const receiverBalance \= await connection.getBalance(receiver.publicKey); console.log("Sender Balance:", \`${senderBalance}\`); console.log("Receiver Balance:", \`${receiverBalance}\`); Console RunClick to execute the code. Transfer SOL import { LAMPORTS\_PER\_SOL, SystemProgram, Transaction, sendAndConfirmTransaction, Keypair, Connection } from "@solana/web3.js"; const connection \= new Connection("http://localhost:8899", "confirmed"); const sender \= new Keypair(); const receiver \= new Keypair(); const signature \= await connection.requestAirdrop( sender.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); const transferInstruction \= SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: receiver.publicKey, lamports: 0.01 \* LAMPORTS\_PER\_SOL }); const transaction \= new Transaction().add(transferInstruction); const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[sender\] ); console.log("Transaction Signature:", \`${transactionSignature}\`); const senderBalance \= await connection.getBalance(sender.publicKey); const receiverBalance \= await connection.getBalance(receiver.publicKey); console.log("Sender Balance:", \`${senderBalance}\`); console.log("Receiver Balance:", \`${receiverBalance}\`); Console RunClick to execute the code. Create a `Connection` to handle sending transactions and fetching account data. In this example, we're connecting to the local test validator which runs on `localhost:8899`. Connection const connection \= new Connection("http://localhost:8899", "confirmed"); Generate new [keypairs](https://solana.com/docs/core/accounts#public-key) to use as the sender and receiver accounts. Generate keypairs const sender \= new Keypair(); const receiver \= new Keypair(); Add SOL to the sender account. On networks other than mainnet, you can use the `requestAirdrop` method to get SOL for testing. Airdrop const signature \= await connection.requestAirdrop( sender.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); The `SystemProgram.transfer()` method creates an instruction that transfers SOL from the `fromPubkey` account to the `toPubkey` account for the specified number of `lamports`. Transfer instruction const transferInstruction \= SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: receiver.publicKey, lamports: 0.01 \* LAMPORTS\_PER\_SOL }); Create a transaction and add the instruction to the transaction. In this example, we're creating a transaction with a single instruction. However, you can add multiple instructions to a transaction. Transaction const transaction \= new Transaction().add(transferInstruction); Sign and send the transaction to the network. The sender keypair is required in the signers array to authorize the transfer of SOL from their account. Send transaction const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[sender\] ); The transaction signature is a unique identifier that can be used to look up the transaction on Solana Explorer. Create a `Connection` to handle sending transactions and fetching account data. In this example, we're connecting to the local test validator which runs on `localhost:8899`. Connection const connection \= new Connection("http://localhost:8899", "confirmed"); Generate new [keypairs](https://solana.com/docs/core/accounts#public-key) to use as the sender and receiver accounts. Generate keypairs const sender \= new Keypair(); const receiver \= new Keypair(); Add SOL to the sender account. On networks other than mainnet, you can use the `requestAirdrop` method to get SOL for testing. Airdrop const signature \= await connection.requestAirdrop( sender.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); The `SystemProgram.transfer()` method creates an instruction that transfers SOL from the `fromPubkey` account to the `toPubkey` account for the specified number of `lamports`. Transfer instruction const transferInstruction \= SystemProgram.transfer({ fromPubkey: sender.publicKey, toPubkey: receiver.publicKey, lamports: 0.01 \* LAMPORTS\_PER\_SOL }); Create a transaction and add the instruction to the transaction. In this example, we're creating a transaction with a single instruction. However, you can add multiple instructions to a transaction. Transaction const transaction \= new Transaction().add(transferInstruction); Sign and send the transaction to the network. The sender keypair is required in the signers array to authorize the transfer of SOL from their account. Send transaction const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[sender\] ); The transaction signature is a unique identifier that can be used to look up the transaction on Solana Explorer. Transfer SOL import { LAMPORTS\_PER\_SOL, SystemProgram, Transaction, sendAndConfirmTransaction, Keypair, Connection } from "@solana/web3.js"; const connection \= new Connection("http://localhost:8899", "confirmed"); [Create a token](https://solana.com/docs/intro/quick-start/writing-to-network#create-a-token) ---------------------------------------------------------------------------------------------- The example below creates a new token on Solana using the Token Extensions Program. This requires two instructions: 1. Invoke the System Program to create a new account. 2. Invoke the Token Extensions Program to initialize that account as a Mint. Create mint account import { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction, LAMPORTS\_PER\_SOL } from "@solana/web3.js"; import { MINT\_SIZE, TOKEN\_2022\_PROGRAM\_ID, createInitializeMint2Instruction, getMinimumBalanceForRentExemptMint, getMint } from "@solana/spl-token"; const connection \= new Connection("http://localhost:8899", "confirmed"); const wallet \= new Keypair(); // Fund the wallet with SOL const signature \= await connection.requestAirdrop( wallet.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); // Generate keypair to use as address of mint account const mint \= new Keypair(); // Calculate lamports required for rent exemption const rentExemptionLamports \= await getMinimumBalanceForRentExemptMint(connection); // Instruction to create new account with space for new mint account const createAccountInstruction \= SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: mint.publicKey, space: MINT\_SIZE, lamports: rentExemptionLamports, programId: TOKEN\_2022\_PROGRAM\_ID }); // Instruction to initialize mint account const initializeMintInstruction \= createInitializeMint2Instruction( mint.publicKey, 2, // decimals wallet.publicKey, // mint authority wallet.publicKey, // freeze authority TOKEN\_2022\_PROGRAM\_ID ); // Build transaction with instructions to create new account and initialize mint account const transaction \= new Transaction().add( createAccountInstruction, initializeMintInstruction ); const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[\ \ wallet, // payer\ \ mint // mint address keypair\ \ \] ); console.log("Transaction Signature:", \`${transactionSignature}\`); const mintData \= await getMint( connection, mint.publicKey, "confirmed", TOKEN\_2022\_PROGRAM\_ID ); console.log( ); Console RunClick to execute the code. Create mint account import { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction, LAMPORTS\_PER\_SOL } from "@solana/web3.js"; import { MINT\_SIZE, TOKEN\_2022\_PROGRAM\_ID, createInitializeMint2Instruction, getMinimumBalanceForRentExemptMint, getMint } from "@solana/spl-token"; const connection \= new Connection("http://localhost:8899", "confirmed"); const wallet \= new Keypair(); // Fund the wallet with SOL const signature \= await connection.requestAirdrop( wallet.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); // Generate keypair to use as address of mint account const mint \= new Keypair(); // Calculate lamports required for rent exemption const rentExemptionLamports \= await getMinimumBalanceForRentExemptMint(connection); // Instruction to create new account with space for new mint account const createAccountInstruction \= SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: mint.publicKey, space: MINT\_SIZE, lamports: rentExemptionLamports, programId: TOKEN\_2022\_PROGRAM\_ID }); // Instruction to initialize mint account const initializeMintInstruction \= createInitializeMint2Instruction( mint.publicKey, 2, // decimals wallet.publicKey, // mint authority wallet.publicKey, // freeze authority TOKEN\_2022\_PROGRAM\_ID ); // Build transaction with instructions to create new account and initialize mint account const transaction \= new Transaction().add( createAccountInstruction, initializeMintInstruction ); const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[\ \ wallet, // payer\ \ mint // mint address keypair\ \ \] ); console.log("Transaction Signature:", \`${transactionSignature}\`); const mintData \= await getMint( connection, mint.publicKey, "confirmed", TOKEN\_2022\_PROGRAM\_ID ); console.log( ); Console RunClick to execute the code. Creating a token requires using both the `@solana/web3.js` and `@solana/spl-token` libraries. The code in the example below will: * Create a connection * Generate a keypair to pay for the transaction * Request an airdrop to fund the keypair Connection & wallet setup const connection \= new Connection("http://localhost:8899", "confirmed"); const wallet \= new Keypair(); const signature \= await connection.requestAirdrop( wallet.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); Generate a keypair for the mint account. The public key will be used as the mint account's address. Mint keypair const mint \= new Keypair(); Calculate the minimum lamports required for a mint account. The `getMinimumBalanceForRentExemptMint` function calculates how many lamport must be allocated for the data on a mint account. Rent exemption const rentExemptionLamports \= await getMinimumBalanceForRentExemptMint(connection); The first instruction invokes the System Program's `createAccount` instruction to: 1. Allocate the number of bytes needed to store the mint data. 2. Transfer lamports from the wallet to fund the new account. 3. Assign ownership of the account to the [Token Extensions program](https://solana.com/docs/tokens/extensions) . Create account instruction const createAccountInstruction \= SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: mint.publicKey, space: MINT\_SIZE, lamports: rentExemptionLamports, programId: TOKEN\_2022\_PROGRAM\_ID }); The second instruction invokes the Token Extensions Program's `createInitializeMint2Instruction` instruction to initialize the mint account with the following data: * 2 decimals * Wallet as both mint authority and freeze authority Initialize mint instruction const initializeMintInstruction \= createInitializeMint2Instruction( mint.publicKey, 2, wallet.publicKey, wallet.publicKey, TOKEN\_2022\_PROGRAM\_ID ); Add both instructions to a single transaction. This ensures that account creation and initialization happen atomically. (Either both instructions succeed, or neither does.) This approach is common when building complex Solana transactions, as it guarantees that all instructions execute together. Transaction const transaction \= new Transaction().add( createAccountInstruction, initializeMintInstruction ); Sign and send the transaction. Two signatures are required: * The wallet account signs as the payer for [transaction fees](https://solana.com/docs/core/fees) and account creation * The mint account signs to authorize the use of its address for the new account Send transaction const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[\ \ wallet,\ \ mint\ \ \] ); The transaction signature returned can be used to inspect the transaction on Solana Explorer. Creating a token requires using both the `@solana/web3.js` and `@solana/spl-token` libraries. The code in the example below will: * Create a connection * Generate a keypair to pay for the transaction * Request an airdrop to fund the keypair Connection & wallet setup const connection \= new Connection("http://localhost:8899", "confirmed"); const wallet \= new Keypair(); const signature \= await connection.requestAirdrop( wallet.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); Generate a keypair for the mint account. The public key will be used as the mint account's address. Mint keypair const mint \= new Keypair(); Calculate the minimum lamports required for a mint account. The `getMinimumBalanceForRentExemptMint` function calculates how many lamport must be allocated for the data on a mint account. Rent exemption const rentExemptionLamports \= await getMinimumBalanceForRentExemptMint(connection); The first instruction invokes the System Program's `createAccount` instruction to: 1. Allocate the number of bytes needed to store the mint data. 2. Transfer lamports from the wallet to fund the new account. 3. Assign ownership of the account to the [Token Extensions program](https://solana.com/docs/tokens/extensions) . Create account instruction const createAccountInstruction \= SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: mint.publicKey, space: MINT\_SIZE, lamports: rentExemptionLamports, programId: TOKEN\_2022\_PROGRAM\_ID }); The second instruction invokes the Token Extensions Program's `createInitializeMint2Instruction` instruction to initialize the mint account with the following data: * 2 decimals * Wallet as both mint authority and freeze authority Initialize mint instruction const initializeMintInstruction \= createInitializeMint2Instruction( mint.publicKey, 2, wallet.publicKey, wallet.publicKey, TOKEN\_2022\_PROGRAM\_ID ); Add both instructions to a single transaction. This ensures that account creation and initialization happen atomically. (Either both instructions succeed, or neither does.) This approach is common when building complex Solana transactions, as it guarantees that all instructions execute together. Transaction const transaction \= new Transaction().add( createAccountInstruction, initializeMintInstruction ); Sign and send the transaction. Two signatures are required: * The wallet account signs as the payer for [transaction fees](https://solana.com/docs/core/fees) and account creation * The mint account signs to authorize the use of its address for the new account Send transaction const transactionSignature \= await sendAndConfirmTransaction( connection, transaction, \[\ \ wallet,\ \ mint\ \ \] ); The transaction signature returned can be used to inspect the transaction on Solana Explorer. Create mint account import { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction, LAMPORTS\_PER\_SOL } from "@solana/web3.js"; import { MINT\_SIZE, TOKEN\_2022\_PROGRAM\_ID, createInitializeMint2Instruction, getMinimumBalanceForRentExemptMint, getMint } from "@solana/spl-token"; const connection \= new Connection("http://localhost:8899", "confirmed"); const wallet \= new Keypair(); const signature \= await connection.requestAirdrop( wallet.publicKey, LAMPORTS\_PER\_SOL ); await connection.confirmTransaction(signature, "confirmed"); Is this page helpful? [Previous\ \ Reading from Network](https://solana.com/docs/intro/quick-start/reading-from-network) [Next\ \ Deploy a Program](https://solana.com/docs/intro/quick-start/deploying-programs) ### Table of Contents [Transfer SOL](https://solana.com/docs/intro/quick-start/writing-to-network#transfer-sol) [Create a token](https://solana.com/docs/intro/quick-start/writing-to-network#create-a-token) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/quick-start/writing-to-network.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Writing to the Network | Solana --- # @solana/react-hooks | Solana [Solana Documentation](https://solana.com/docs) [Frontend](https://solana.com/docs/frontend) [@solana/react-hooks](https://solana.com/docs/frontend/react-hooks) ==================================================================== Copy MarkdownOpen `@solana/react-hooks` layers a React provider, hooks, and suspense friendly query helpers on top of `@solana/client`. You still configure a single client, but the hooks expose wallet state, balances, transactions, and program queries without wiring stores or subscriptions by hand. [Install](https://solana.com/docs/frontend/react-hooks#install) ---------------------------------------------------------------- Terminal $ npm install @solana/client @solana/react-hooks Copy Both packages are required because the hooks reuse the client runtime to manage wallets, RPC, and caches. [Wrap your tree once](https://solana.com/docs/frontend/react-hooks#wrap-your-tree-once) ---------------------------------------------------------------------------------------- Create the client, optionally pick wallet connectors, then wrap your React tree with `SolanaProvider`. Every hook reads from the shared client instance. "use client"; import { autoDiscover, createClient } from "@solana/client"; import { SolanaProvider } from "@solana/react-hooks"; const client \= createClient({ endpoint: "https://api.devnet.solana.com", websocketEndpoint: "wss://api.devnet.solana.com", walletConnectors: autoDiscover(), }); export function Providers({ children }: { children: React.ReactNode }) { return {children}; } [Hooks mirror the client runtime](https://solana.com/docs/frontend/react-hooks#hooks-mirror-the-client-runtime) ---------------------------------------------------------------------------------------------------------------- * **Wallet + connectors**: `useWallet`, `useWalletConnection`, `useConnectWallet`, and `useDisconnectWallet` expose the same registry that powers the client. * **Balance + account watchers**: `useBalance`, `useAccount`, `useSolBalance`, and `useProgramAccounts` stream updates from the underlying watchers and share cache with actions. * **Transactions + SPL helpers**: `useSolTransfer`, `useSplToken`, `useTransactionPool`, and `useSendTransaction` lean on the client's helper suite so hooks inherit blockhash refresh, fee payer resolution, and logging. function WalletPanel() { const { connectors, connect, disconnect, wallet, status } \= useWalletConnection(); const balance \= useBalance(wallet?.account.address); if (status \=== "connected") { return ( {wallet?.account.address.toString()} Lamports: {balance.lamports?.toString() ?? "loading…"} Disconnect ); } return ( {connectors.map((connector) \=> ( connect(connector.id)}\> Connect {connector.name} ))} ); } [Query + caching patterns](https://solana.com/docs/frontend/react-hooks#query--caching-patterns) ------------------------------------------------------------------------------------------------- `SolanaQueryProvider` layers React Query-compatible primitives on top of the client store so Solana-specific queries can suspend, refetch, and sync with program subscriptions. import { SolanaQueryProvider, useProgramAccounts } from "@solana/react-hooks"; function ProgramAccounts({ program }: { program: string }) { const query \= useProgramAccounts(program); if (query.isLoading) return Loading…; if (query.isError) return RPC error; return ( query.refresh()}\>Refresh {query.accounts.map(({ pubkey }) \=> ( {pubkey.toString()} ))} ); } export function ProgramAccountsSection({ program }: { program: string }) { return ( ); } [Transaction flows made declarative](https://solana.com/docs/frontend/react-hooks#transaction-flows-made-declarative) ---------------------------------------------------------------------------------------------------------------------- Hooks expose the same transaction helpers as the client but manage loading and error states for you. Use them for SOL transfers, SPL token flows, or arbitrary instruction batches. import { useSolTransfer } from "@solana/react-hooks"; function SolTransferForm({ destination }: { destination: string }) { const transfer \= useSolTransfer(); return ( { event.preventDefault(); void transfer.send({ destination, lamports: 100\_000\_000n }); }} \> {transfer.isSending ? "Sending…" : "Send 0.1 SOL"} {transfer.signature ? Signature: {transfer.signature} : null} {transfer.error ? {String(transfer.error)} : null} ); } Need raw instructions instead? `useSendTransaction` accepts `instructions` and optional `prepare` overrides, handing you signature and status tracking when the request finishes. import { useSendTransaction, useWallet } from "@solana/react-hooks"; import { getTransferSolInstruction } from "@solana-program/system"; import { address, lamports } from "@solana/kit"; function CustomTransactionForm({ destination }: { destination: string }) { const wallet \= useWallet(); const { send, isSending, signature, error } \= useSendTransaction(); async function handleSend() { if (wallet.status !== "connected") return; const instruction \= getTransferSolInstruction({ source: wallet.session.account, destination: address(destination), amount: lamports(100\_000\_000n), }); await send({ instructions: \[instruction\] }); } return ( {isSending ? "Sending…" : "Send 0.1 SOL"} {signature ? Signature: {signature} : null} {error ? {String(error)} : null} ); } [Common patterns for Solana devs](https://solana.com/docs/frontend/react-hooks#common-patterns-for-solana-devs) ---------------------------------------------------------------------------------------------------------------- * **Shared runtime, multiple apps**: Configure the client once (maybe in a core package) and consume it in web, mobile web, or embedded React islands. * **UI first development**: Hooks mirror the most common Solana flows (connecting a wallet, fetching balances, sending SOL, reading SPL balances) so you can focus on UX instead of RPC plumbing. * **Progressive enhancement**: Start headless with `@solana/client`, then add hooks in the areas where you want React state and suspense friendly data fetching. * **Testing**: Mock the hook return values or pass a mocked client to `SolanaProvider` to simulate wallets, RPC successes, or failures in unit tests. * **Server components aware**: Only mark leaf components that call hooks with `"use client"`; everything else can stay on the server and receive hydrated props from hook powered children. Pair this guide with the [@solana/client overview](https://solana.com/docs/frontend/client) to understand the runtime each hook builds upon. Is this page helpful? [Previous\ \ @solana/client](https://solana.com/docs/frontend/client) [Next\ \ @solana/web3-compat](https://solana.com/docs/frontend/web3-compat) ### Table of Contents [Install](https://solana.com/docs/frontend/react-hooks#install) [Wrap your tree once](https://solana.com/docs/frontend/react-hooks#wrap-your-tree-once) [Hooks mirror the client runtime](https://solana.com/docs/frontend/react-hooks#hooks-mirror-the-client-runtime) [Query + caching patterns](https://solana.com/docs/frontend/react-hooks#query--caching-patterns) [Transaction flows made declarative](https://solana.com/docs/frontend/react-hooks#transaction-flows-made-declarative) [Common patterns for Solana devs](https://solana.com/docs/frontend/react-hooks#common-patterns-for-solana-devs) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/frontend/react-hooks.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Introductory commands for getting started on the Anchor CLI | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Installation](https://solana.com/docs/intro/installation) [Anchor CLI Basics](https://solana.com/docs/intro/installation/anchor-cli-basics) ================================================================================== Copy MarkdownOpen This section provides some common commands and examples to help you get started using the [Anchor CLI](https://www.anchor-lang.com/docs) . ### [Initialize the project](https://solana.com/docs/intro/installation/anchor-cli-basics#initialize-the-project) Create a new Anchor project by running the command shown below. It will create a new directory with the project name and use it to initialize a new Anchor project. Terminal $ anchor init Copy For example, the command below will create a project called `my-project`. The `my-project` directory will contain a basic Rust program and TypeScript test template. Terminal $ anchor init my-project Copy Then navigate to the project directory: Terminal $ cd Copy See Anchor's [project file structure](https://www.anchor-lang.com/docs/quickstart/local#project-file-structure) . ### [Build the program](https://solana.com/docs/intro/installation/anchor-cli-basics#build-the-program) To build your project, run the following command: Terminal $ anchor build Copy You can find the compiled program in the `/target/deploy` directory. When running `anchor build`, if you encounter the following errors: ### error: not a directory ### lock file version 4 requires \`-Znext-lockfile-bump After applying the preceding solution, attempt to run `anchor build` again. ### [Deploy the program](https://solana.com/docs/intro/installation/anchor-cli-basics#deploy-the-program) To deploy your project, run the following command: Terminal $ anchor deploy Copy This command deploys your program to the `cluster` specified in the [`Anchor.toml`](https://www.anchor-lang.com/docs/references/anchor-toml) file. ### [Test the program](https://solana.com/docs/intro/installation/anchor-cli-basics#test-the-program) To test your project, run the following command: Terminal $ anchor test Copy This command builds, deploys, and runs the tests for your project. When using the `localnet` cluster, Anchor automatically starts a local validator, deploys the program, runs tests, then stops the validator. Either of the following errors may indicate that you don't have Node.js or Yarn installed: Permission denied (os error 13) No such file or directory (os error 2) Is this page helpful? [Previous\ \ Solana CLI Basics](https://solana.com/docs/intro/installation/solana-cli-basics) [Next\ \ Surfpool CLI Basics](https://solana.com/docs/intro/installation/surfpool-cli-basics) ### Table of Contents [Initialize the project](https://solana.com/docs/intro/installation/anchor-cli-basics#initialize-the-project) [Build the program](https://solana.com/docs/intro/installation/anchor-cli-basics#build-the-program) [Deploy the program](https://solana.com/docs/intro/installation/anchor-cli-basics#deploy-the-program) [Test the program](https://solana.com/docs/intro/installation/anchor-cli-basics#test-the-program) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/installation/anchor-cli-basics.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Send Payments | Solana [Payments](https://solana.com/docs) [Send Payments](https://solana.com/docs/payments/send-payments) ================================================================ Copy MarkdownOpen Whether you're building payroll disbursements, vendor payouts, or cross-border remittances, sending payments on Solana means sub-second settlement, sub-cent fees, and no intermediaries taking a cut. Attach memos for reconciliation, batch hundreds of payments into a single transaction, or sponsor fees so your users never need to hold SOL. This section covers the core patterns for moving stablecoins—from single transfers to high-volume payment processing. [### Basic Payment\ \ Learn how to send a single token transfer between wallets.](https://solana.com/docs/payments/send-payments/basic-payment) [### Payment with Memo\ \ Learn how to attach invoice IDs or notes to a payment.](https://solana.com/docs/payments/send-payments/payment-with-memo) [### Payment Processing\ \ Learn how to batch payments and sponsor transaction fees.](https://solana.com/docs/payments/send-payments/payment-processing) Is this page helpful? [Previous\ \ Interacting with Solana](https://solana.com/docs/payments/interacting-with-solana) [Next\ \ Basic Payment](https://solana.com/docs/payments/send-payments/basic-payment) ### Table of Contents No Headings [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/send-payments/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # getLatestBlockhash RPC Method | Solana [Solana Documentation](https://solana.com/docs) [Solana RPC Methods](https://solana.com/docs/rpc) [HTTP Methods](https://solana.com/docs/rpc/http) [getLatestBlockhash RPC Method](https://solana.com/docs/rpc/http/getlatestblockhash) ===================================================================================== Copy MarkdownOpen Returns the latest blockhash Version Restriction This method is only available in `solana-core` v1.9 or newer. Please use [getRecentBlockhash](https://solana.com/docs/rpc/http/getrecentblockhash) for `solana-core` v1.8 and below. #### params objectoptional Configuration object containing the following fields: commitmentstring minContextSlotnumber #### result object RpcResponse JSON object with `value` field set to a JSON object including: blockhashstring lastValidBlockHeightu64 cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getLatestBlockhash", \> "params": \[\ \ \> {\ \ \> "commitment": "processed"\ \ \> }\ \ \> \] \> } \> ' Try it Response { "jsonrpc": "2.0", "result": { "context": { "slot": 2792 }, "value": { "blockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "lastValidBlockHeight": 3090 } }, "id": 1 } cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getLatestBlockhash", \> "params": \[\ \ \> {\ \ \> "commitment": "processed"\ \ \> }\ \ \> \] \> } \> ' Try it #### params objectoptional Configuration object containing the following fields: commitmentstring minContextSlotnumber #### result Response { "jsonrpc": "2.0", "result": { "context": { "slot": 2792 }, "value": { "blockhash": "EkSnNWid2cvwEVnVx9aBqawnmiCNiDgp3gUdkDPTKN1N", "lastValidBlockHeight": 3090 } }, "id": 1 } object RpcResponse JSON object with `value` field set to a JSON object including: blockhashstring lastValidBlockHeightu64 Is this page helpful? [Previous\ \ getLargestAccounts](https://solana.com/docs/rpc/http/getlargestaccounts) [Next\ \ getLeaderSchedule](https://solana.com/docs/rpc/http/getleaderschedule) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # getAccountInfo RPC Method | Solana [Solana Documentation](https://solana.com/docs) [Solana RPC Methods](https://solana.com/docs/rpc) [HTTP Methods](https://solana.com/docs/rpc/http) [getAccountInfo RPC Method](https://solana.com/docs/rpc/http/getaccountinfo) ============================================================================= Copy MarkdownOpen Returns all information associated with the account of provided Pubkey #### params stringrequired Pubkey of account to query, as base-58 encoded string. objectoptional Configuration object. commitmentstring encodingstring dataSliceobject minContextSlotnumber #### result object | null If the requested account doesn't exist result will be `null`. Otherwise, an object containing: datastring | \[string,encoding\] | object executablebool lamportsu64 ownerstring rentEpochu64 spaceu64 cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getAccountInfo", \> "params": \[\ \ \> "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",\ \ \> {\ \ \> "commitment": "finalized",\ \ \> "encoding": "base58"\ \ \> }\ \ \> \] \> } \> ' Try it Response { "jsonrpc": "2.0", "result": { "context": { "apiVersion": "2.0.15", "slot": 341197053 }, "value": { "data": \["", "base58"\], "executable": false, "lamports": 88849814690250, "owner": "11111111111111111111111111111111", "rentEpoch": 18446744073709551615, "space": 0 } }, "id": 1 } cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getAccountInfo", \> "params": \[\ \ \> "vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg",\ \ \> {\ \ \> "commitment": "finalized",\ \ \> "encoding": "base58"\ \ \> }\ \ \> \] \> } \> ' Try it #### params stringrequired Pubkey of account to query, as base-58 encoded string. objectoptional Configuration object. commitmentstring encodingstring dataSliceobject minContextSlotnumber #### result Response { "jsonrpc": "2.0", "result": { "context": { "apiVersion": "2.0.15", "slot": 341197053 }, "value": { "data": \["", "base58"\], "executable": false, "lamports": 88849814690250, "owner": "11111111111111111111111111111111", "rentEpoch": 18446744073709551615, "space": 0 } }, "id": 1 } object | null If the requested account doesn't exist result will be `null`. Otherwise, an object containing: datastring | \[string,encoding\] | object executablebool lamportsu64 ownerstring rentEpochu64 spaceu64 Is this page helpful? [Previous\ \ HTTP Methods](https://solana.com/docs/rpc/http) [Next\ \ getBalance](https://solana.com/docs/rpc/http/getbalance) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter getAccountInfo RPC Method | Solana --- # Solana wallet integration with Next.js and @solana/react-hooks | Solana [Solana Documentation](https://solana.com/docs) [Frontend](https://solana.com/docs/frontend) [Next.js + Solana React Hooks](https://solana.com/docs/frontend/nextjs-solana) =============================================================================== Copy MarkdownOpen Set up a minimal Solana wallet integration in Next.js (App Router) with `@solana/client` and `@solana/react-hooks`. You'll create a connect wallet dropdown and a SOL transfer component. Next.js Hooks App [Resources](https://solana.com/docs/frontend/nextjs-solana#resources) ---------------------------------------------------------------------- * [Framework Kit Repository](https://github.com/solana-foundation/framework-kit) * [Solana JSON RPC](https://docs.solana.com/cluster/rpc-endpoints) [Prerequisites](https://solana.com/docs/frontend/nextjs-solana#prerequisites) ------------------------------------------------------------------------------ * Node 20+ * npm [Create Next.js Project](https://solana.com/docs/frontend/nextjs-solana#create-nextjs-project) ----------------------------------------------------------------------------------------------- Terminal $ npx create-next-app@latest my-app Copy $ cd my-app Copy When prompted, accept all defaults (the starter includes Tailwind, which this tutorial uses for simple utility styles). ### [Install Solana dependencies](https://solana.com/docs/frontend/nextjs-solana#install-solana-dependencies) Terminal $ npm install @solana/client@latest @solana/react-hooks@latest @solana/kit@latest Copy Use `@latest` to stay current. If your package manager surfaces peer warnings, you can pin to the current tested set (`@solana/client@1.1.0 @solana/react-hooks@1.1.0 @solana/kit@5.0.0`) and upgrade when new releases land. 1\. Create Solana Provider -------------------------- `app/providers.tsx` uses the simplified `SolanaProvider` props. Set the cluster (Devnet by default). 2\. Update Layout ----------------- Wrap your application with the `Providers` component. Update `app/layout.tsx` to import and use it: This wraps the entire app with the Solana context so all child components can access wallet state and hooks. 3\. Wallet Connect Button ------------------------- Dropdown to connect/disconnect Wallet Standard wallets via `useConnectWallet` / `useDisconnectWallet`. Wallet dropdown options Wallet dropdown connected 4\. SOL Transfer ---------------- Use `useSolTransfer` to send a SOL transfer (lamports) to any address. SOL transfer form filled SOL transfer success Connectors are the same Wallet Standard set (Phantom/Solflare/Backpack/auto-discovery); once connected, SOL transfers use the connected signer. 5\. Page -------- `app/page.tsx` renders the wallet connect and SOL transfer components (no Suspense needed): 6\. Run the Application ----------------------- Terminal $ npm run dev Copy Open [http://localhost:3000](http://localhost:3000/) , connect a Devnet wallet, and send a SOL transfer. 1\. Create Solana Provider -------------------------- `app/providers.tsx` uses the simplified `SolanaProvider` props. Set the cluster (Devnet by default). 2\. Update Layout ----------------- Wrap your application with the `Providers` component. Update `app/layout.tsx` to import and use it: This wraps the entire app with the Solana context so all child components can access wallet state and hooks. 3\. Wallet Connect Button ------------------------- Dropdown to connect/disconnect Wallet Standard wallets via `useConnectWallet` / `useDisconnectWallet`. Wallet dropdown options Wallet dropdown connected 4\. SOL Transfer ---------------- Use `useSolTransfer` to send a SOL transfer (lamports) to any address. SOL transfer form filled SOL transfer success Connectors are the same Wallet Standard set (Phantom/Solflare/Backpack/auto-discovery); once connected, SOL transfers use the connected signer. 5\. Page -------- `app/page.tsx` renders the wallet connect and SOL transfer components (no Suspense needed): 6\. Run the Application ----------------------- Terminal $ npm run dev Copy Open [http://localhost:3000](http://localhost:3000/) , connect a Devnet wallet, and send a SOL transfer. app providers.tsx "use client"; import type { SolanaClientConfig } from "@solana/client"; import { SolanaProvider } from "@solana/react-hooks"; const defaultConfig: SolanaClientConfig \= { cluster: "devnet", rpc: "https://api.devnet.solana.com", websocket: "wss://api.devnet.solana.com", }; export default function Providers({ children }: { children: React.ReactNode }) { return {children}; } Is this page helpful? [Previous\ \ @solana/web3-compat](https://solana.com/docs/frontend/web3-compat) [Next\ \ Rust SDK](https://solana.com/docs/clients/official/rust) ### Table of Contents [Resources](https://solana.com/docs/frontend/nextjs-solana#resources) [Prerequisites](https://solana.com/docs/frontend/nextjs-solana#prerequisites) [Create Next.js Project](https://solana.com/docs/frontend/nextjs-solana#create-nextjs-project) [Install Solana dependencies](https://solana.com/docs/frontend/nextjs-solana#install-solana-dependencies) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/frontend/nextjs-solana.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Developing Programs in Rust | Solana [Solana Documentation](https://solana.com/docs) Developing Programs [Developing Programs in Rust](https://solana.com/docs/programs/rust) ===================================================================== Copy MarkdownOpen Solana programs are primarily developed using the Rust programming language. This page focuses on writing Solana programs in Rust without using the Anchor framework, an approach often referred to as writing "native Rust" programs. Native Rust development provides developers with direct control over their Solana programs. However, this approach requires more manual setup and boilerplate code compared to using the Anchor framework. This method is recommended for developers who: * Seek granular control over program logic and optimizations * Want to learn the underlying concepts before moving to higher-level frameworks For beginners, we recommend starting with the Anchor framework. See the [Anchor](https://www.anchor-lang.com/docs) section for more information. [Prerequisites](https://solana.com/docs/programs/rust#prerequisites) --------------------------------------------------------------------- For detailed installation instructions, visit the [installation](https://solana.com/docs/intro/installation) page. Before you begin, ensure you have the following installed: * Rust: The programming language for building Solana programs. * Solana CLI: Command-line tool for Solana development. [Getting Started](https://solana.com/docs/programs/rust#getting-started) ------------------------------------------------------------------------- The example below covers the basic steps to create your first Solana program written in Rust. We'll create a minimal program that prints "Hello, world!" to the program log. Create a new program -------------------- First, create a new Rust project using the standard `cargo new` command with the `--lib` flag. Terminal $ cargo new hello\_world --lib Copy Navigate to the project directory. You should see the default `src/lib.rs` and `Cargo.toml` files Terminal $ cd hello\_world Copy Update the `edition` field in `Cargo.toml` to `2021`. Otherwise, you might encounter an error when building the program. Add the solana-program dependency --------------------------------- Next, add the `solana-program` dependency. This is the minimum dependency required to build a Solana program. Terminal $ cargo add solana-program@2.2.0 Copy Add the crate-type ------------------ Next, add the following snippet to `Cargo.toml`. Cargo.toml \[lib\] crate-type = \["cdylib", "lib"\] If you don't include this config, the `target/deploy` directory will not be generated when you build the program. Your `Cargo.toml` file should look like the following: Cargo.toml \[package\] name = "hello\_world" version = "0.1.0" edition = "2021" \[lib\] crate-type = \["cdylib", "lib"\] \[dependencies\] solana-program = "2.2.0" Add the program code -------------------- Next, replace the contents of `src/lib.rs` with the following code. This is a minimal Solana program that prints "Hello, world!" to the program log when the program is invoked. The `msg!` macro is used in Solana programs to print a message to the program log. src/lib.rs use solana\_program::{ account\_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, }; entrypoint!(process\_instruction); pub fn process\_instruction( \_program\_id: &Pubkey, \_accounts: &\[AccountInfo\], \_instruction\_data: &\[u8\], ) \-> ProgramResult { msg!("Hello, world!"); Ok(()) } Build the program ----------------- Next, build the program using the `cargo build-sbf` command. Terminal $ cargo build-sbf Copy This command generates a `target/deploy` directory containing two important files: 1. A `.so` file (e.g., `hello_world.so`): This is the compiled Solana program that will be deployed to the network as a "smart contract". 2. A keypair file (e.g., `hello_world-keypair.json`): The public key of this keypair is used as the program ID when deploying the program. To view the program ID, run the following command in your terminal. This command prints the public key of the keypair at the specified file path: Terminal $ solana address -k ./target/deploy/hello\_world-keypair.json Copy Example output: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz Add test dependencies --------------------- Next, test the program using the `litesvm` crate. Add the following dependencies to `Cargo.toml`. Terminal $ cargo add litesvm@0.6.1 --dev Copy $ cargo add solana-sdk@2.2.0 --dev Copy Test the program ---------------- Add the following test to `src/lib.rs`, below the program code. This is a test module that invokes the hello world program. src/lib.rs use solana\_program::{ account\_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, }; entrypoint!(process\_instruction); pub fn process\_instruction( \_program\_id: &Pubkey, \_accounts: &\[AccountInfo\], \_instruction\_data: &\[u8\], ) \-> ProgramResult { msg!("Hello, world!"); Ok(()) } #\[cfg(test)\] mod test { use litesvm::LiteSVM; use solana\_sdk::{ instruction::Instruction, message::Message, signature::{Keypair, Signer}, transaction::Transaction, }; #\[test\] fn test\_hello\_world() { // Create a new LiteSVM instance let mut svm \= LiteSVM::new(); // Create a keypair for the transaction payer let payer \= Keypair::new(); // Airdrop some lamports to the payer svm.airdrop(&payer.pubkey(), 1\_000\_000\_000).unwrap(); // Load our program let program\_keypair \= Keypair::new(); let program\_id \= program\_keypair.pubkey(); svm.add\_program\_from\_file(program\_id, "target/deploy/hello\_world.so") .unwrap(); // Create instruction with no accounts and no data let instruction \= Instruction { program\_id, accounts: vec!\[\], data: vec!\[\], }; // Create transaction let message \= Message::new(&\[instruction\], Some(&payer.pubkey())); let transaction \= Transaction::new(&\[&payer\], message, svm.latest\_blockhash()); // Send transaction and verify it succeeds let result \= svm.send\_transaction(transaction); assert!(result.is\_ok(), "Transaction should succeed"); let logs \= result.unwrap().logs; println!("Logs: {logs:#?}"); } } Run the test using the `cargo test` command. The program log will display "Hello, world!". Terminal $ cargo test -- --no-capture Copy Example output: Terminal running 1 test Logs: \[\ \ "Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk invoke \[1\]",\ \ "Program log: Hello, world!",\ \ "Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk consumed 211 of 200000 compute units",\ \ "Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk success",\ \ \] test test::test\_hello\_world ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s Deploy the program ------------------ Next, deploy the program. When developing locally, we can use the `solana-test-validator`. First, configure the Solana CLI to use the local Solana cluster. Terminal $ solana config set -ul Copy Example output: Config File: /.config/solana/cli/config.yml RPC URL: http://localhost:8899 WebSocket URL: ws://localhost:8900/ (computed) Keypair Path: /.config/solana/id.json Commitment: confirmed Open a new terminal and run the `solana-test-validators` command to start the local validator. Terminal $ solana-test-validator Copy While the test validator is running, run the `solana program deploy` command in a separate terminal to deploy the program to the local validator. Terminal $ solana program deploy ./target/deploy/hello\_world.so Copy Example output: Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz Signature: 5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH You can inspect the program ID and transaction signature on [Solana Explorer](https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899) . Note that the cluster on Solana Explorer must also be localhost. The "Custom RPC URL" option on Solana Explorer defaults to `http://localhost:8899`. Create example client --------------------- Next, we'll demonstrate how to invoke the program using a Rust client. First create an `examples` directory and a `client.rs` file. Terminal $ mkdir -p examples && touch examples/client.rs Copy Add the following to `Cargo.toml`. Cargo.toml \[\[example\]\] name = "client" path = "examples/client.rs" Add `solana-client` and `tokio` dependencies. Terminal $ cargo add solana-client@2.2.0 --dev Copy $ cargo add tokio --dev Copy Add the client -------------- Add the following code to `examples/client.rs`. This is a Rust client script that funds a new keypair to pay for transaction fees and then invokes the hello world program. examples/client.rs use solana\_client::rpc\_client::RpcClient; use solana\_sdk::{ commitment\_config::CommitmentConfig, instruction::Instruction, pubkey::Pubkey, signature::{Keypair, Signer}, transaction::Transaction, }; use std::str::FromStr; #\[tokio::main\] async fn main() { // Program ID (replace with your actual program ID) let program\_id \= Pubkey::from\_str("4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz").unwrap(); // Connect to the Solana devnet let rpc\_url \= String::from("http://localhost:8899"); let client \= RpcClient::new\_with\_commitment(rpc\_url, CommitmentConfig::confirmed()); // Generate a new keypair for the payer let payer \= Keypair::new(); // Request airdrop let airdrop\_amount \= 1\_000\_000\_000; // 1 SOL let signature \= client .request\_airdrop(&payer.pubkey(), airdrop\_amount) .expect("Failed to request airdrop"); // Wait for airdrop confirmation loop { let confirmed \= client.confirm\_transaction(&signature).unwrap(); if confirmed { break; } } // Create the instruction let instruction \= Instruction::new\_with\_borsh( program\_id, &(), // Empty instruction data vec!\[\], // No accounts needed ); // Add the instruction to new transaction let mut transaction \= Transaction::new\_with\_payer(&\[instruction\], Some(&payer.pubkey())); transaction.sign(&\[&payer\], client.get\_latest\_blockhash().unwrap()); // Send and confirm the transaction match client.send\_and\_confirm\_transaction(&transaction) { Ok(signature) \=> println!("Transaction Signature: {}", signature), Err(err) \=> eprintln!("Error sending transaction: {}", err), } } Replace the program ID ---------------------- Before running the client code, replace the program ID in the code snippet with the one for your program. You can get your program ID by running the following command. Terminal $ solana address -k ./target/deploy/hello\_world-keypair.json Copy Invoke the program ------------------ Run the client script with the following command. Terminal $ cargo run --example client Copy Example output: Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV You can inspect the transaction signature on [Solana Explorer](https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899) (local cluster) to see "Hello, world!" in the program log. Update the program ------------------ Solana programs can be updated by redeploying to the same program ID. Update the program in `src/lib.rs` to print "Hello, Solana!" instead of "Hello, world!". lib.rs pub fn process\_instruction( \_program\_id: &Pubkey, \_accounts: &\[AccountInfo\], \_instruction\_data: &\[u8\], ) \-> ProgramResult { \- msg!("Hello, world!"); + msg!("Hello, Solana!"); Ok(()) } Run the `cargo build-sbf` command to generate an updated `.so` file. Terminal $ cargo build-sbf Copy Test the updated program by running the `cargo test` command. Terminal $ cargo test -- --no-capture Copy You should see "Hello, Solana!" in the program log. Terminal running 1 test Logs: \[\ \ "Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV invoke \[1\]",\ \ "Program log: Hello, Solana!",\ \ "Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV consumed 211 of 200000 compute units",\ \ "Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV success",\ \ \] test test::test\_hello\_world ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s Redeploy the program -------------------- Redeploy the program using the same `solana program deploy` command. Terminal $ solana program deploy ./target/deploy/hello\_world.so Copy Run the client code again and inspect the transaction signature on Solana Explorer to see "Hello, Solana!" in the program log. Terminal $ cargo run --example client Copy Close the program ----------------- You can close your Solana program to reclaim the SOL allocated to the account. Closing a program is irreversible, so it should be done with caution. To close a program, use the `solana program close ` command. For example: Terminal $ solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz --bypass-warning Copy Example output: Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL reclaimed Note that once a program is closed, its program ID cannot be reused. Attempting to deploy a program with a previously closed program ID will result in an error. Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, use a new Program Id Redeploy a closed program ------------------------- If you need to redeploy a program with the same source code after closing a program, you must generate a new program ID. To generate a new keypair for the program, run the following command: Terminal $ solana-keygen new -o ./target/deploy/hello\_world-keypair.json --force Copy Alternatively, you can delete the existing keypair file (e.g. `./target/deploy/hello_world-keypair.json`) and run `cargo build-sbf` again, which will generate a new keypair file. Create a new program -------------------- First, create a new Rust project using the standard `cargo new` command with the `--lib` flag. Terminal $ cargo new hello\_world --lib Copy Navigate to the project directory. You should see the default `src/lib.rs` and `Cargo.toml` files Terminal $ cd hello\_world Copy Update the `edition` field in `Cargo.toml` to `2021`. Otherwise, you might encounter an error when building the program. Add the solana-program dependency --------------------------------- Next, add the `solana-program` dependency. This is the minimum dependency required to build a Solana program. Terminal $ cargo add solana-program@2.2.0 Copy Add the crate-type ------------------ Next, add the following snippet to `Cargo.toml`. Cargo.toml \[lib\] crate-type = \["cdylib", "lib"\] If you don't include this config, the `target/deploy` directory will not be generated when you build the program. Add the program code -------------------- Next, replace the contents of `src/lib.rs` with the following code. This is a minimal Solana program that prints "Hello, world!" to the program log when the program is invoked. The `msg!` macro is used in Solana programs to print a message to the program log. Build the program ----------------- Next, build the program using the `cargo build-sbf` command. Terminal $ cargo build-sbf Copy This command generates a `target/deploy` directory containing two important files: 1. A `.so` file (e.g., `hello_world.so`): This is the compiled Solana program that will be deployed to the network as a "smart contract". 2. A keypair file (e.g., `hello_world-keypair.json`): The public key of this keypair is used as the program ID when deploying the program. To view the program ID, run the following command in your terminal. This command prints the public key of the keypair at the specified file path: Terminal $ solana address -k ./target/deploy/hello\_world-keypair.json Copy Example output: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz Add test dependencies --------------------- Next, test the program using the `litesvm` crate. Add the following dependencies to `Cargo.toml`. Terminal $ cargo add litesvm@0.6.1 --dev Copy $ cargo add solana-sdk@2.2.0 --dev Copy Test the program ---------------- Add the following test to `src/lib.rs`, below the program code. This is a test module that invokes the hello world program. Run the test using the `cargo test` command. The program log will display "Hello, world!". Terminal $ cargo test -- --no-capture Copy Example output: Terminal running 1 test Logs: \[\ \ "Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk invoke \[1\]",\ \ "Program log: Hello, world!",\ \ "Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk consumed 211 of 200000 compute units",\ \ "Program 9528phXNvdWp5kkR4rgpoeZvR8ZWT5THVywK95YRprkk success",\ \ \] test test::test\_hello\_world ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s Deploy the program ------------------ Next, deploy the program. When developing locally, we can use the `solana-test-validator`. First, configure the Solana CLI to use the local Solana cluster. Terminal $ solana config set -ul Copy Example output: Config File: /.config/solana/cli/config.yml RPC URL: http://localhost:8899 WebSocket URL: ws://localhost:8900/ (computed) Keypair Path: /.config/solana/id.json Commitment: confirmed Open a new terminal and run the `solana-test-validators` command to start the local validator. Terminal $ solana-test-validator Copy While the test validator is running, run the `solana program deploy` command in a separate terminal to deploy the program to the local validator. Terminal $ solana program deploy ./target/deploy/hello\_world.so Copy Example output: Program Id: 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz Signature: 5osMiNMiDZGM7L1e2tPHxU8wdB8gwG8fDnXLg5G7SbhwFz4dHshYgAijk4wSQL5cXiu8z1MMou5kLadAQuHp7ybH You can inspect the program ID and transaction signature on [Solana Explorer](https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899) . Note that the cluster on Solana Explorer must also be localhost. The "Custom RPC URL" option on Solana Explorer defaults to `http://localhost:8899`. Create example client --------------------- Next, we'll demonstrate how to invoke the program using a Rust client. First create an `examples` directory and a `client.rs` file. Terminal $ mkdir -p examples && touch examples/client.rs Copy Add the following to `Cargo.toml`. Cargo.toml \[\[example\]\] name = "client" path = "examples/client.rs" Add `solana-client` and `tokio` dependencies. Terminal $ cargo add solana-client@2.2.0 --dev Copy $ cargo add tokio --dev Copy Add the client -------------- Add the following code to `examples/client.rs`. This is a Rust client script that funds a new keypair to pay for transaction fees and then invokes the hello world program. Replace the program ID ---------------------- Before running the client code, replace the program ID in the code snippet with the one for your program. You can get your program ID by running the following command. Terminal $ solana address -k ./target/deploy/hello\_world-keypair.json Copy Invoke the program ------------------ Run the client script with the following command. Terminal $ cargo run --example client Copy Example output: Transaction Signature: 54TWxKi3Jsi3UTeZbhLGUFX6JQH7TspRJjRRFZ8NFnwG5BXM9udxiX77bAACjKAS9fGnVeEazrXL4SfKrW7xZFYV You can inspect the transaction signature on [Solana Explorer](https://explorer.solana.com/?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899) (local cluster) to see "Hello, world!" in the program log. Update the program ------------------ Solana programs can be updated by redeploying to the same program ID. Update the program in `src/lib.rs` to print "Hello, Solana!" instead of "Hello, world!". lib.rs pub fn process\_instruction( \_program\_id: &Pubkey, \_accounts: &\[AccountInfo\], \_instruction\_data: &\[u8\], ) \-> ProgramResult { \- msg!("Hello, world!"); + msg!("Hello, Solana!"); Ok(()) } Run the `cargo build-sbf` command to generate an updated `.so` file. Terminal $ cargo build-sbf Copy Test the updated program by running the `cargo test` command. Terminal $ cargo test -- --no-capture Copy You should see "Hello, Solana!" in the program log. Terminal running 1 test Logs: \[\ \ "Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV invoke \[1\]",\ \ "Program log: Hello, Solana!",\ \ "Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV consumed 211 of 200000 compute units",\ \ "Program 5y8bHrnwfq2dLDgLn3WoTHb9dDuyorj9gyapW6aeyrpV success",\ \ \] test test::test\_hello\_world ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s Redeploy the program -------------------- Redeploy the program using the same `solana program deploy` command. Terminal $ solana program deploy ./target/deploy/hello\_world.so Copy Run the client code again and inspect the transaction signature on Solana Explorer to see "Hello, Solana!" in the program log. Terminal $ cargo run --example client Copy Close the program ----------------- You can close your Solana program to reclaim the SOL allocated to the account. Closing a program is irreversible, so it should be done with caution. To close a program, use the `solana program close ` command. For example: Terminal $ solana program close 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz --bypass-warning Copy Example output: Closed Program Id 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz, 0.1350588 SOL reclaimed Note that once a program is closed, its program ID cannot be reused. Attempting to deploy a program with a previously closed program ID will result in an error. Error: Program 4Ujf5fXfLx2PAwRqcECCLtgDxHKPznoJpa43jUBxFfMz has been closed, use a new Program Id Redeploy a closed program ------------------------- If you need to redeploy a program with the same source code after closing a program, you must generate a new program ID. To generate a new keypair for the program, run the following command: Terminal $ solana-keygen new -o ./target/deploy/hello\_world-keypair.json --force Copy Alternatively, you can delete the existing keypair file (e.g. `./target/deploy/hello_world-keypair.json`) and run `cargo build-sbf` again, which will generate a new keypair file. src lib.rs Cargo.toml \[package\] name = "hello\_world" version = "0.1.0" edition = "2021" \[dependencies\] Is this page helpful? [Previous\ \ Transfer Tokens](https://solana.com/docs/tokens/extensions/confidential-transfer/transfer-tokens) [Next\ \ Program Structure](https://solana.com/docs/programs/rust/program-structure) ### Table of Contents [Prerequisites](https://solana.com/docs/programs/rust#prerequisites) [Getting Started](https://solana.com/docs/programs/rust#getting-started) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/programs/rust/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Developing Programs in Rust | Solana --- # @solana/web3-compat | Solana [Solana Documentation](https://solana.com/docs) [Frontend](https://solana.com/docs/frontend) [@solana/web3-compat](https://solana.com/docs/frontend/web3-compat) ==================================================================== Copy MarkdownOpen `@solana/web3-compat` is the bridge between long-lived `@solana/web3.js` apps and the newer Kit runtime. Swap the import, keep the surface that your app already knows, and progressively adopt Kit features without rewriting every helper or instruction at once. [Install with Kit peers](https://solana.com/docs/frontend/web3-compat#install-with-kit-peers) ---------------------------------------------------------------------------------------------- Terminal $ npm install @solana/web3-compat @solana/kit @solana/client Copy The compatibility layer re-exports classic Web3 types (`Connection`, `PublicKey`, `Transaction`, etc.) while internally delegating to Kit networking and codecs. Keep your existing RPC endpoints, but benefit from Kit's more predictable blockhash handling and wallet abstractions. [Replace imports (no other code changes)](https://solana.com/docs/frontend/web3-compat#replace-imports-no-other-code-changes) ------------------------------------------------------------------------------------------------------------------------------ Most projects can migrate file-by-file by switching the import source. Both named and namespace imports mirror the old package. Before import { Connection, PublicKey } from "@solana/web3.js"; After import { Connection, PublicKey } from "@solana/web3-compat"; CommonJS works too: const solanaWeb3 \= require("@solana/web3-compat"); const connection \= new solanaWeb3.Connection("https://api.devnet.solana.com"); Behind the scenes `Connection` forwards reads and writes through `@solana/client`, so helpers like `sendAndConfirmTransaction`, `simulateTransaction`, and `getProgramAccounts` benefit from the newer runtime without touching your business logic. [Bridge helpers when you need Kit types](https://solana.com/docs/frontend/web3-compat#bridge-helpers-when-you-need-kit-types) ------------------------------------------------------------------------------------------------------------------------------ As you adopt Kit directly (maybe in new components using `@solana/client` or `@solana/react-hooks`), use the bridge helpers shipped in the compat package to convert between the two ecosystems: import { PublicKey, toAddress, toPublicKey, toWeb3Instruction, toKitSigner, } from "@solana/web3-compat"; const legacyKey \= new PublicKey("11111111111111111111111111111111"); const kitAddress \= toAddress(legacyKey); const backToWeb3 \= toPublicKey(kitAddress); Mixing runtimes becomes safe: newer hooks can emit Kit instructions, then `toWeb3Instruction` will wrap them for legacy flows until the whole project moves over. [Progressive migration patterns](https://solana.com/docs/frontend/web3-compat#progressive-migration-patterns) -------------------------------------------------------------------------------------------------------------- * **Incremental rollouts**: Update one feature folder at a time. When a module no longer needs compat, point it straight at `@solana/client`/`@solana/react-hooks` without touching the rest of the tree. * **Shared RPC tuning**: Because compat relies on Kit connections, tuning commitment levels, prioritization fees, or RPC URLs flows through a single config object. * **SPL + transaction helpers**: Keep legacy transaction builders for now, but reach for `client.helpers.transaction.prepare` once you're ready. Compat can still submit the same signed payloads. * **Testing**: Reuse existing Web3 mocks since the public surface stays identical, yet under test you can stub the Kit client for richer simulations. [What ships in Phase 0](https://solana.com/docs/frontend/web3-compat#what-ships-in-phase-0) -------------------------------------------------------------------------------------------- * `Connection` with `getLatestBlockhash`, `getBalance`, `getAccountInfo`, `getProgramAccounts`, `getSignatureStatuses`, `sendRawTransaction`, `confirmTransaction`, and `simulateTransaction`. * Utilities like `LAMPORTS_PER_SOL`, `sendAndConfirmTransaction`, and `compileFromCompat`. * `SystemProgram.transfer` plus all core Web3 primitives (`Keypair`, `Transaction`, `VersionedTransaction`, `TransactionInstruction`). Coverage is still expanding Methods outside the list above fall back to legacy `@solana/web3.js` today. Keep the old dependency around until the rest of your surface lands in compat, and track future releases for subscription support and broader RPC coverage. Pair this guide with the [@solana/client overview](https://solana.com/docs/frontend/client) and [@solana/react-hooks guide](https://solana.com/docs/frontend/react-hooks) when you are ready to start building new UI on top of the same Kit runtime. Is this page helpful? [Previous\ \ @solana/react-hooks](https://solana.com/docs/frontend/react-hooks) [Next\ \ Next.js + Solana React Hooks](https://solana.com/docs/frontend/nextjs-solana) ### Table of Contents [Install with Kit peers](https://solana.com/docs/frontend/web3-compat#install-with-kit-peers) [Replace imports (no other code changes)](https://solana.com/docs/frontend/web3-compat#replace-imports-no-other-code-changes) [Bridge helpers when you need Kit types](https://solana.com/docs/frontend/web3-compat#bridge-helpers-when-you-need-kit-types) [Progressive migration patterns](https://solana.com/docs/frontend/web3-compat#progressive-migration-patterns) [What ships in Phase 0](https://solana.com/docs/frontend/web3-compat#what-ships-in-phase-0) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/frontend/web3-compat.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Deploy Your First Solana Program | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Quick Start](https://solana.com/docs/intro/quick-start) [Deploy Your First Solana Program](https://solana.com/docs/intro/quick-start/deploying-programs) ================================================================================================= Copy MarkdownOpen Build, deploy, and test your first [program](https://solana.com/docs/core/programs) to the Solana Blockchain using the Anchor framework. This guide will help you become more familiar with the Solana Playground and prepare you to use program derived addresses (PDA) and cross-program invocation (CPI). ### [Create Anchor Project](https://solana.com/docs/intro/quick-start/deploying-programs#create-anchor-project) 1. Open the [Solana Playground](https://beta.solpg.io/) in your web browser 2. On the left panel, click **\+ Create a new project** 3. Enter a **Project name** 4. Select **Anchor (Rust)** as the framework 5. Click **Create** New Project The `src/lib.rs` source file will open. It contains one struct called `Initialize`, which does the following: * Receives a required parameter called `data: u64` * Creates a new account * Saves the value of `data: u64` to the new account * Adds a message to the transaction's program logs lib.rs use anchor\_lang::prelude::\*; // This is your program's public key and it will update // automatically when you build the project. declare\_id!("11111111111111111111111111111111"); #\[program\] mod hello\_anchor { use super::\*; pub fn initialize(ctx: Context, data: u64) \-> Result<()> { ctx.accounts.new\_account.data \= data; msg!("Changed data to: {}!", data); // Message will show up in the tx logs Ok(()) } } #\[derive(Accounts)\] pub struct Initialize<'info\> { // We must specify the space in order to initialize an account. // First 8 bytes are default account discriminator, // next 8 bytes come from NewAccount.data being type u64. // (u64 = 64 bits unsigned integer = 8 bytes) #\[account(\ \ init,\ \ payer \= signer,\ \ space \= 8 + 8\ \ )\] pub new\_account: Account<'info, NewAccount\>, #\[account(mut)\] pub signer: Signer<'info\>, pub system\_program: Program<'info, System\>, } #\[account\] pub struct NewAccount { data: u64 } ### Explanation ### [Build and Deploy the Program](https://solana.com/docs/intro/quick-start/deploying-programs#build-and-deploy-the-program) 1. Compile the program code Terminal $ build Copy \[show output\] Your [program ID](https://solana.com/docs/intro/quick-start/deploying-programs) , defined in `declare_id!()`, will now be updated. 2. Add SOL to your wallet _(Optional)_ Deploying a program requires SOL in the program's on-chain account. If necessary, [add SOL to your wallet](https://solana.com/docs/intro/quick-start#add-sol-to-your-wallet) before proceeding to step 3. 3. Deploy the program to the network Terminal $ deploy Copy \[show output\] When deployed, the program's bytecode is stored in an executable program account. **Note:** If preferred, you can use the **Build** and **Deploy** buttons on the left-side panel, as shown in the screenshot below. Build and Deploy ### [Test the Program](https://solana.com/docs/intro/quick-start/deploying-programs#test-the-program) 1. Open the test file called `tests/anchor.test.ts`. This file demonstrates how to invoke the program's `initialize` struct from the client. anchor.test.ts // No imports needed: web3, anchor, pg and more are globally available describe("Test", () \=> { it("initialize", async () \=> { // Generate keypair for the new account const newAccountKp \= new web3.Keypair(); // Send transaction const data \= new BN(42); const txHash \= await pg.program.methods .initialize(data) .accounts({ newAccount: newAccountKp.publicKey, signer: pg.wallet.publicKey, systemProgram: web3.SystemProgram.programId }) .signers(\[newAccountKp\]) .rpc(); console.log(\`Use 'solana confirm -v ${txHash}' to see the logs\`); // Confirm transaction await pg.connection.confirmTransaction(txHash); // Fetch the created account const newAccount \= await pg.program.account.newAccount.fetch( newAccountKp.publicKey ); console.log("On-chain data is:", newAccount.data.toString()); // Check whether the data on-chain is equal to local 'data' assert(data.eq(newAccount.data)); }); }); 2. Run the test file Terminal $ test Copy \[show output\] 3. Store the transaction hash (`TxHash`) included in the output (In the example above, the transaction hash is `3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc`.) **Note:** If preferred, you can use the `Test` button on the left-side panel. Run Test 4. Run `solana confirm -v [TxHash]` to view the transaction logs Terminal $ solana confirm -v 3TewJtiUz1EgtT88pLJHvKFzqrzDNuHVi8CfD2mWmHEBAaMfC5NAaHdmr19qQYfTiBace6XUmADvR4Qrhe8gH5uc Copy \[show output\] 4. View the transaction details Open either [SolanaFM](https://solana.fm/) or [Solana Explorer](https://explorer.solana.com/?cluster=devnet) and search for the transaction hash. **Solana Explorer:** Set the network cluster to `devnet`, to match that of the Solana Playground. ### [Close the Program](https://solana.com/docs/intro/quick-start/deploying-programs#close-the-program) Close the program to recover the SOL allocated to the on-chain program. To do so, run `solana program close [ProgramID]`, using the program address stored in the `declare_id!()` macro. Terminal $ solana program close 2VvQ11q8xrn5tkPNyeraRsPaATdiPx8weLAD8aD4dn2r Copy \[show output\] Programs can **only** be closed or updated by an account with upgrade authority. Your Playground wallet automatically becomes the upgrade authority for each program when it is deployed. If the upgrade authority is revoked, the program becomes immutable. Congratulations! You built and deployed your first Solana program using Anchor. [Next steps](https://solana.com/docs/intro/quick-start/deploying-programs#next-steps) -------------------------------------------------------------------------------------- Now that you have deployed your first program, you are ready to explore [program-derived addresses](https://solana.com/docs/intro/quick-start/program-derived-address) and [cross-program invocation](https://solana.com/docs/intro/quick-start/cross-program-invocation) . Is this page helpful? [Previous\ \ Writing to the Network](https://solana.com/docs/intro/quick-start/writing-to-network) [Next\ \ Creating Deterministic Accounts](https://solana.com/docs/intro/quick-start/program-derived-address) ### Table of Contents [Create Anchor Project](https://solana.com/docs/intro/quick-start/deploying-programs#create-anchor-project) [Build and Deploy the Program](https://solana.com/docs/intro/quick-start/deploying-programs#build-and-deploy-the-program) [Test the Program](https://solana.com/docs/intro/quick-start/deploying-programs#test-the-program) [Close the Program](https://solana.com/docs/intro/quick-start/deploying-programs#close-the-program) [Next steps](https://solana.com/docs/intro/quick-start/deploying-programs#next-steps) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/quick-start/deploying-programs.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Deploying Programs | Solana [Solana Documentation](https://solana.com/docs) Developing Programs [Deploying Programs](https://solana.com/docs/programs/deploying) ================================================================= Copy MarkdownOpen This section walks through the basic process of deploying a Solana program using the Solana CLI. [CLI Command Reference](https://solana.com/docs/programs/deploying#cli-command-reference) ------------------------------------------------------------------------------------------ | Task | Command | | --- | --- | | Build program | `cargo build-sbf` | | Deploy new program | `solana program deploy ` | | Update existing program | `solana program deploy ` (same as deploy) | | Show program info | `solana program show ` | | Transfer program authority | `solana program set-upgrade-authority --new-upgrade-authority ` | | Make program immutable | `solana program set-upgrade-authority --final` | | Close program | `solana program close --bypass-warning` | | Check wallet balance | `solana balance` | | Request airdrop (devnet/localhost) | `solana airdrop 2` | [Key Concepts](https://solana.com/docs/programs/deploying#key-concepts) ------------------------------------------------------------------------ Before diving in, let's clarify some terminology: * **Program ID**: The on-chain address of your program. Users interact with your program by referencing the Program ID. * **Program Account**: The on-chain account that stores your program's metadata. The program account's address is the Program ID. The program account also stores the address of the ProgramData Account. * **ProgramData Account**: The on-chain account that stores your program's deployed executable code. * **Program Authority**: The account that has permission to update or close the program. By default, this is your CLI wallet. [Prerequisites](https://solana.com/docs/programs/deploying#prerequisites) -------------------------------------------------------------------------- ### [Install the Solana CLI](https://solana.com/docs/programs/deploying#install-the-solana-cli) First, [install the Solana CLI](https://solana.com/docs/intro/installation) . ### [Set Up Wallet](https://solana.com/docs/programs/deploying#set-up-wallet) After installation, create a local keypair wallet. The address of this wallet is set as the default program authority when deploying programs: Terminal $ solana-keygen new Copy This creates a keypair at `~/.config/solana/id.json` by default. ### [Configure Cluster](https://solana.com/docs/programs/deploying#configure-cluster) Choose which Solana cluster to deploy to. Use the `solana config get` command to check your current configuration: Terminal $ solana config get Copy \[show output\] Switch between clusters as needed: Terminal $ solana config set --url mainnet-beta Copy $ solana config set --url devnet Copy $ solana config set --url localhost Copy $ solana config set --url testnet Copy $ solana config set --url "https://your-rpc-url.com" Copy ### [Fund Wallet](https://solana.com/docs/programs/deploying#fund-wallet) You'll need SOL to pay for program deployments. The amount depends on your program size. For devnet or localhost, fund your wallet using the `solana airdrop` command: Terminal $ solana airdrop 2 Copy \[show output\] Check your wallet balance: Terminal $ solana balance Copy \[show output\] [Basic Operations](https://solana.com/docs/programs/deploying#basic-operations) -------------------------------------------------------------------------------- ### [Build Program](https://solana.com/docs/programs/deploying#build-program) To build a program, use the `cargo build-sbf` command: Terminal $ cargo build-sbf Copy Example Program --------------- Here is a minimal Solana program that prints "Hello, Solana!" to the program logs. src/lib.rs use solana\_program::{ account\_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, }; entrypoint!(process\_instruction); pub fn process\_instruction( \_program\_id: &Pubkey, \_accounts: &\[AccountInfo\], \_instruction\_data: &\[u8\], ) \-> ProgramResult { msg!("Hello, Solana!"); Ok(()) } Build Output ------------ Build your program using the `cargo build-sbf` command: Terminal $ cargo build-sbf Copy This creates two important files in `target/deploy/`: 1. `hello_world-keypair.json`: A keypair file whose public key will be used as your Program ID 2. `hello_world.so`: The compiled program executable Example Program --------------- Here is a minimal Solana program that prints "Hello, Solana!" to the program logs. Build Output ------------ Build your program using the `cargo build-sbf` command: Terminal $ cargo build-sbf Copy This creates two important files in `target/deploy/`: 1. `hello_world-keypair.json`: A keypair file whose public key will be used as your Program ID 2. `hello_world.so`: The compiled program executable src lib.rs Cargo.toml use solana\_program::{ account\_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, }; entrypoint!(process\_instruction); pub fn process\_instruction( \_program\_id: &Pubkey, \_accounts: &\[AccountInfo\], \_instruction\_data: &\[u8\], ) \-> ProgramResult { msg!("Hello, Solana!"); Ok(()) } ### [Check Program Size and Cost](https://solana.com/docs/programs/deploying#check-program-size-and-cost) Deploying a program requires SOL to be allocated to the program account based on the size of the program. Larger programs cost more SOL to deploy. Check your program's size: Terminal $ wc -c < ./target/deploy/hello\_world.so Copy \[show output\] Calculate the required SOL for this size (bytes): Terminal $ solana rent 18504 Copy \[show output\] You'll need slightly more SOL than shown to cover deployment transaction fees. ### [Deploy Program](https://solana.com/docs/programs/deploying#deploy-program) Use the `solana program deploy` command to deploy your program: Terminal $ solana program deploy ./target/deploy/hello\_world.so Copy \[show output\] The **Program Id** shown is your program's permanent address on the network. To deploy with a specific Program ID (instead of the auto-generated one), use: Terminal $ solana program deploy ./target/deploy/hello\_world.so --program-id ./custom-keypair.json Copy You can generate new keypairs using the `solana-keygen` command: Terminal $ solana-keygen new -o ./custom-keypair.json Copy ### [Update Program](https://solana.com/docs/programs/deploying#update-program) Update your program using the same `solana program deploy` command: 1. Make changes to your program code 2. Rebuild your program: `cargo build-sbf` 3. Deploy the update: Terminal $ solana program deploy ./target/deploy/hello\_world.so Copy \[show output\] If your updated program requires more space (bytes) than currently allocated, the deployment will automatically extend the program account. This happens when your new program is larger than the previous version. The program account needs additional bytes to store the new program. The CLI will calculate the required SOL and deduct it from your wallet automatically. You can also manually extend a program to allocate more bytes: Terminal $ solana program extend 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE 1000 Copy \[show output\] [Program Management](https://solana.com/docs/programs/deploying#program-management) ------------------------------------------------------------------------------------ Once your program is deployed, there are several common commands to manage the program account. ### [View Program Metadata](https://solana.com/docs/programs/deploying#view-program-metadata) To check your program metadata, use the `solana program show` command: Terminal $ solana program show 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE Copy Example output: $ solana program show 7283x8k8fyBcfaFLyPsxbd2VV1AMmZFP7FNoyTXVKJw7 Program Id: 7283x8k8fyBcfaFLyPsxbd2VV1AMmZFP7FNoyTXVKJw7 Owner: BPFLoaderUpgradeab1e11111111111111111111111 ProgramData Address: Gqn7YQVCP8NtYV1qkEqR4Udhj8EJ3fkikvS7HskCNQ7c Authority: 5kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1 Last Deployed In Slot: 6573 Data Length: 18504 (0x4848) bytes Balance: 0.12999192 SOL ### [Transfer Program Authority](https://solana.com/docs/programs/deploying#transfer-program-authority) To transfer the program authority to a different account, use the `solana program set-upgrade-authority` command: Terminal $ solana program set-upgrade-authority 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE --new-upgrade-authority ./new-authority-keypair.json Copy After transferring the program authority, you can no longer update the program unless you have access to the new authority keypair. ### [Make Your Program Immutable](https://solana.com/docs/programs/deploying#make-your-program-immutable) To make your program immutable, use the `solana program set-upgrade-authority` command with the `--final` flag to remove the program authority: Terminal $ solana program set-upgrade-authority 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE --final Copy \[show output\] Once a program is immutable, it can never be updated or closed. ### [Close Your Program](https://solana.com/docs/programs/deploying#close-your-program) To close your program and reclaim the SOL allocated to the program account, use the `solana program close` command: Terminal $ solana program close 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE --bypass-warning Copy \[show output\] Once closed, the Program ID can not be reused. You cannot deploy a new program to the same address. [Utility Commands](https://solana.com/docs/programs/deploying#utility-commands) -------------------------------------------------------------------------------- ### [List All Programs](https://solana.com/docs/programs/deploying#list-all-programs) View all programs where your current wallet is the authority: Terminal $ solana program show --programs Copy Example output: Program Id | Slot | Authority | Balance \-------------------------------------------------|------------|------------------------------------------------|------------- 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE | 249885434 | 5kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1 | 0.12999192 3KSGCk4m5hqJkTjPHBXUCPcqMwJnK3VmkqEsFUKKGJPK | 249883212 | 5kh6HxYZiAebF8HWLsUWod2EaQQ6iWHpHYCz8UcmFbM1 | 0.28654328 ### [Download a Deployed Program](https://solana.com/docs/programs/deploying#download-a-deployed-program) To download a deployed program, use the `solana program dump` command: Terminal $ solana program dump 7NxQjW8H8hVcqBKgXbVDWqGQCovHbqDW9p1SJJwUyTpE ./downloaded\_program.so Copy \[show output\] [Advanced Options](https://solana.com/docs/programs/deploying#advanced-options) -------------------------------------------------------------------------------- ### [Deployment Flags](https://solana.com/docs/programs/deploying#deployment-flags) When the Solana network is congested, use these flags to help with program deployment. Example Usage: Terminal $ solana program deploy ./target/deploy/hello\_world.so \\ \--with-compute-unit-price 10000 \\ \--max-sign-attempts 10 \\ \--use-rpc Copy Options explained: * **`--with-compute-unit-price`**: Set priority fee in micro-lamports (0.000001 SOL) per compute unit. Check [Helius Priority Fee API](https://docs.helius.dev/guides/priority-fee-api) for current rates. A priority fee is an additional fee that paid to the current leader to prioritize your transaction. * **`--max-sign-attempts`**: Number of times to retry with a new blockhash if transactions expire. (Default: 5) * **`--use-rpc`**: Send transactions to the configured RPC. This flag requires a [stake-weighted](https://solana.com/developers/guides/advanced/stake-weighted-qos) RPC connection from providers such as [Triton](https://triton.one/) or [Helius](https://www.helius.dev/) . Is this page helpful? [Previous\ \ Mollusk](https://solana.com/docs/programs/testing/mollusk) [Next\ \ Generating Clients](https://solana.com/docs/programs/codama/clients) ### Table of Contents [CLI Command Reference](https://solana.com/docs/programs/deploying#cli-command-reference) [Key Concepts](https://solana.com/docs/programs/deploying#key-concepts) [Prerequisites](https://solana.com/docs/programs/deploying#prerequisites) [Install the Solana CLI](https://solana.com/docs/programs/deploying#install-the-solana-cli) [Set Up Wallet](https://solana.com/docs/programs/deploying#set-up-wallet) [Configure Cluster](https://solana.com/docs/programs/deploying#configure-cluster) [Fund Wallet](https://solana.com/docs/programs/deploying#fund-wallet) [Basic Operations](https://solana.com/docs/programs/deploying#basic-operations) [Build Program](https://solana.com/docs/programs/deploying#build-program) [Check Program Size and Cost](https://solana.com/docs/programs/deploying#check-program-size-and-cost) [Deploy Program](https://solana.com/docs/programs/deploying#deploy-program) [Update Program](https://solana.com/docs/programs/deploying#update-program) [Program Management](https://solana.com/docs/programs/deploying#program-management) [View Program Metadata](https://solana.com/docs/programs/deploying#view-program-metadata) [Transfer Program Authority](https://solana.com/docs/programs/deploying#transfer-program-authority) [Make Your Program Immutable](https://solana.com/docs/programs/deploying#make-your-program-immutable) [Close Your Program](https://solana.com/docs/programs/deploying#close-your-program) [Utility Commands](https://solana.com/docs/programs/deploying#utility-commands) [List All Programs](https://solana.com/docs/programs/deploying#list-all-programs) [Download a Deployed Program](https://solana.com/docs/programs/deploying#download-a-deployed-program) [Advanced Options](https://solana.com/docs/programs/deploying#advanced-options) [Deployment Flags](https://solana.com/docs/programs/deploying#deployment-flags) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/programs/deploying.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Introductory commands for getting started on the Surfpool CLI | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Installation](https://solana.com/docs/intro/installation) [Surfpool CLI Basics](https://solana.com/docs/intro/installation/surfpool-cli-basics) ====================================================================================== Copy MarkdownOpen Surfpool is a local development tool that simplifies Solana development by automatically loading programs and accounts from a cluster (mainnet, devnet). Use the Surfpool CLI to start a local validator for testing your programs and transactions. Visit the [Surfpool documentation](https://docs.surfpool.run/) for more information. [Start a local validator](https://solana.com/docs/intro/installation/surfpool-cli-basics#start-a-local-validator) ------------------------------------------------------------------------------------------------------------------ To start a local validator, run the following command: Terminal $ surfpool start Copy By default, Surfpool automatically loads any programs and accounts your transactions depend on from mainnet to the local validator. [Surfpool Studio](https://solana.com/docs/intro/installation/surfpool-cli-basics#surfpool-studio) -------------------------------------------------------------------------------------------------- Surfpool Studio provides a web-based interface for interacting with your local validator. Use it to: * View transactions details * Inspect account data * Airdrop SOL and other tokens using the UI faucet To access Surfpool Studio: 1. Start your local validator with `surfpool start` 2. Open your browser and navigate to [http://127.0.0.1:18488](http://127.0.0.1:18488/) Is this page helpful? [Previous\ \ Anchor CLI Basics](https://solana.com/docs/intro/installation/anchor-cli-basics) [Next\ \ Quick Start](https://solana.com/docs/intro/quick-start) ### Table of Contents [Start a local validator](https://solana.com/docs/intro/installation/surfpool-cli-basics#start-a-local-validator) [Surfpool Studio](https://solana.com/docs/intro/installation/surfpool-cli-basics#surfpool-studio) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/installation/surfpool-cli-basics.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Introductory commands for getting started on the Surfpool CLI | Solana --- # Basic Payment | Solana [Payments](https://solana.com/docs) [Send Payments](https://solana.com/docs/payments/send-payments) [Basic Payment](https://solana.com/docs/payments/send-payments/basic-payment) ============================================================================== Copy MarkdownOpen Solana enables instant, global token transfers with fees under $0.001. Whether you're building cross-border remittances, payroll disbursements, or treasury operations, a basic stablecoin payment settles in under a second and costs a fraction of a cent. [How It Works](https://solana.com/docs/payments/send-payments/basic-payment#how-it-works) ------------------------------------------------------------------------------------------ A payment moves stablecoins from the sender's token account to the recipient's token account. If the recipient is receiving this token for the first time, their token account can be created as part of the same transaction. See [How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) for core payment concepts. The `splToken` helper from [`@solana/client`](https://solana.com/docs/frontend/client) handles ATA derivation, decimal conversion, and transaction building automatically. This is ideal for single payment transfers. The steps below show the core flow. See the [Demo](https://solana.com/docs/payments/send-payments/basic-payment#demo) for complete runnable code. Create the Token Helper ----------------------- Configure the `splToken()` helper by calling `client.splToken()` with the mint address. The helper provides methods for common token operations. Setting `tokenProgram: "auto"` automatically detects whether the mint account is owned by Token or Token-2022 program. Basic Payment const client \= createClient({ endpoint: "http://localhost:8899", websocketEndpoint: "ws://localhost:8900", commitment: "confirmed" }); const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); Send the Payment ---------------- Use `sendTransfer()` to transfer tokens between wallets. The method handles: * **ATA Resolution**: Automatically derives Associated Token Accounts (ATAs) for the sender and recipient. If the recipient's ATA doesn't exist, the instruction to create the account is automatically added to the same transaction. * **Decimal Conversion**: Accepts token amounts and automatically converts to base units based on the mint's decimals (e.g. 0.25 tokens -> 250000 base units, if the mint has 6 decimals) * **Transaction Building**: Creates, signs, and sends the transaction with the transfer instruction Basic Payment const client \= createClient({ endpoint: "http://localhost:8899", websocketEndpoint: "ws://localhost:8900", commitment: "confirmed" }); const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); const signature \= await splToken.sendTransfer({ amount: 0.25, authority: sender, destinationOwner: recipient.address }); Verify Balances --------------- After the transfer completes, use `fetchBalance()` to verify the token balances. This method takes a wallet address and automatically derives the corresponding ATA to fetch the balance. Basic Payment const client \= createClient({ endpoint: "http://localhost:8899", websocketEndpoint: "ws://localhost:8900", commitment: "confirmed" }); const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); const signature \= await splToken.sendTransfer({ amount: 0.25, authority: sender, destinationOwner: recipient.address }); const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); Create the Token Helper ----------------------- Configure the `splToken()` helper by calling `client.splToken()` with the mint address. The helper provides methods for common token operations. Setting `tokenProgram: "auto"` automatically detects whether the mint account is owned by Token or Token-2022 program. Send the Payment ---------------- Use `sendTransfer()` to transfer tokens between wallets. The method handles: * **ATA Resolution**: Automatically derives Associated Token Accounts (ATAs) for the sender and recipient. If the recipient's ATA doesn't exist, the instruction to create the account is automatically added to the same transaction. * **Decimal Conversion**: Accepts token amounts and automatically converts to base units based on the mint's decimals (e.g. 0.25 tokens -> 250000 base units, if the mint has 6 decimals) * **Transaction Building**: Creates, signs, and sends the transaction with the transfer instruction Verify Balances --------------- After the transfer completes, use `fetchBalance()` to verify the token balances. This method takes a wallet address and automatically derives the corresponding ATA to fetch the balance. Basic Payment const client \= createClient({ endpoint: "http://localhost:8899", websocketEndpoint: "ws://localhost:8900", commitment: "confirmed" }); const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); ### [Demo](https://solana.com/docs/payments/send-payments/basic-payment#demo) Demo // Click ">" icon on left to expand demo imports // Generate keypairs for sender and recipient const sender \= (await generateKeypair()).signer; const recipient \= (await generateKeypair()).signer; console.log("Sender Address:", sender.address); console.log("Recipient Address:", recipient.address); // Demo Setup: Create client, mint account, token accounts, and fund with initial tokens const { client, mint } \= await demoSetup(sender, recipient); console.log("\\nMint Address:", mint.address); // ============================================================================= // Basic Token Payment Demo // ============================================================================= // Create splToken helper for this mint using @solana/client const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); // Transfer tokens from sender to recipient (ATA and decimals handled automatically) const signature \= await splToken.sendTransfer({ amount: 0.25, authority: sender, destinationOwner: recipient.address }); console.log("\\n\=== Token Payment Complete ==="); console.log("Transaction Signature:", signature.toString()); // Fetch final token account balances using splToken helper const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); console.log("\\nSender Token Account Balance:", senderBalance); console.log("Recipient Token Account Balance:", recipientBalance); // ============================================================================= // Demo Setup Helper Function // ============================================================================= Console RunClick to execute the code. Demo // Click ">" icon on left to expand demo imports // Generate keypairs for sender and recipient const sender \= (await generateKeypair()).signer; const recipient \= (await generateKeypair()).signer; console.log("Sender Address:", sender.address); console.log("Recipient Address:", recipient.address); // Demo Setup: Create client, mint account, token accounts, and fund with initial tokens const { client, mint } \= await demoSetup(sender, recipient); console.log("\\nMint Address:", mint.address); // ============================================================================= // Basic Token Payment Demo // ============================================================================= // Create splToken helper for this mint using @solana/client const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); // Transfer tokens from sender to recipient (ATA and decimals handled automatically) const signature \= await splToken.sendTransfer({ amount: 0.25, authority: sender, destinationOwner: recipient.address }); console.log("\\n\=== Token Payment Complete ==="); console.log("Transaction Signature:", signature.toString()); // Fetch final token account balances using splToken helper const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); console.log("\\nSender Token Account Balance:", senderBalance); console.log("Recipient Token Account Balance:", recipientBalance); // ============================================================================= // Demo Setup Helper Function // ============================================================================= Console RunClick to execute the code. Is this page helpful? [Previous\ \ Send Payments](https://solana.com/docs/payments/send-payments) [Next\ \ Payment with Memo](https://solana.com/docs/payments/send-payments/payment-with-memo) ### Table of Contents [How It Works](https://solana.com/docs/payments/send-payments/basic-payment#how-it-works) [Demo](https://solana.com/docs/payments/send-payments/basic-payment#demo) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/send-payments/basic-payment.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Limitations | Solana [Solana Documentation](https://solana.com/docs) Developing Programs [Limitations](https://solana.com/docs/programs/limitations) ============================================================ Copy MarkdownOpen Developing programs on the Solana blockchain has some inherent limitations associated with it. Below is a list of common limitations that you may run into. [Rust libraries](https://solana.com/docs/programs/limitations#rust-libraries) ------------------------------------------------------------------------------ Since Rust based onchain programs must be deterministic while running in a resource-constrained, single-threaded environment, they have some limitations on various libraries. On-chain Rust programs support most of Rust's libstd, libcore, and liballoc, as well as many 3rd party crates. There are some limitations since these programs run in a resource-constrained, single-threaded environment, as well as being deterministic: * No access to * `rand` * `std::fs` * `std::net` * `std::future` * `std::process` * `std::sync` * `std::task` * `std::thread` * `std::time` * Limited access to: * `std::hash` * `std::os` * Bincode is extremely computationally expensive in both cycles and call depth and should be avoided * String formatting should be avoided since it is also computationally expensive. * No support for `println!`, `print!`, use the [`msg!`](https://github.com/solana-labs/solana/blob/d9b0fc0e3eec67dfe4a97d9298b15969b2804fab/sdk/program/src/log.rs#L33) macro instead. * The runtime enforces a limit on the number of instructions a program can execute during the processing of one instruction. See [computation budget](https://solana.com/docs/core/fees#compute-budget) for more information. [Compute budget](https://solana.com/docs/programs/limitations#compute-budget) ------------------------------------------------------------------------------ To prevent abuse of the blockchain's computational resources, each transaction is allocated a [compute budget](https://solana.com/docs/references/terminology#compute-budget) . Exceeding this compute budget will result in the transaction failing. See the [computational constraints](https://solana.com/docs/core/fees#compute-budget) documentation for more specific details. [Call stack depth - `CallDepthExceeded` error](https://solana.com/docs/programs/limitations#call-stack-depth---calldepthexceeded-error) ---------------------------------------------------------------------------------------------------------------------------------------- Solana programs are constrained to run quickly, and to facilitate this, the program's call stack is limited to a max depth of **64 frames**. When a program exceeds the allowed call stack depth limit, it will receive the `CallDepthExceeded` error. [CPI call depth - `CallDepth` error](https://solana.com/docs/programs/limitations#cpi-call-depth---calldepth-error) -------------------------------------------------------------------------------------------------------------------- Cross-program invocations allow programs to invoke other programs directly, but the depth is constrained currently to `4`. When a program exceeds the allowed [cross-program invocation call depth](https://solana.com/docs/core/cpi) , it will receive a `CallDepth` error [Float Rust types support](https://solana.com/docs/programs/limitations#float-rust-types-support) -------------------------------------------------------------------------------------------------- Programs support a limited subset of Rust's float operations. If a program attempts to use a float operation that is not supported, the runtime will report an unresolved symbol error. Float operations are performed via software libraries, specifically LLVM's float built-ins. Due to the software emulated, they consume more compute units than integer operations. In general, fixed point operations are recommended where possible. The [Solana Program Library math](https://github.com/solana-labs/solana-program-library/tree/master/libraries/math) tests will report the performance of some math operations. To run the test, sync the repo and run: cargo test-sbf \-- --nocapture --test-threads=1 Recent results show the float operations take more instructions compared to integers equivalents. Fixed point implementations may vary but will also be less than the float equivalents: u64 f32 Multiply 8 176 Divide 9 219 [Static writable data](https://solana.com/docs/programs/limitations#static-writable-data) ------------------------------------------------------------------------------------------ Program shared objects do not support writable shared data. Programs are shared between multiple parallel executions using the same shared read-only code and data. This means that developers should not include any static writable or global variables in programs. In the future a copy-on-write mechanism could be added to support writable data. [Signed division](https://solana.com/docs/programs/limitations#signed-division) -------------------------------------------------------------------------------- The SBF instruction set does not support signed division. Is this page helpful? [Previous\ \ Program Examples](https://solana.com/docs/programs/examples) [Next\ \ Frontend](https://solana.com/docs/frontend) ### Table of Contents [Rust libraries](https://solana.com/docs/programs/limitations#rust-libraries) [Compute budget](https://solana.com/docs/programs/limitations#compute-budget) [Call stack depth - `CallDepthExceeded` error](https://solana.com/docs/programs/limitations#call-stack-depth---calldepthexceeded-error) [CPI call depth - `CallDepth` error](https://solana.com/docs/programs/limitations#cpi-call-depth---calldepth-error) [Float Rust types support](https://solana.com/docs/programs/limitations#float-rust-types-support) [Static writable data](https://solana.com/docs/programs/limitations#static-writable-data) [Signed division](https://solana.com/docs/programs/limitations#signed-division) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/programs/limitations.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Limitations | Solana --- # Payment Processing | Solana [Payments](https://solana.com/docs) [Send Payments](https://solana.com/docs/payments/send-payments) [Payment Processing](https://solana.com/docs/payments/send-payments/payment-processing) ======================================================================================== Copy MarkdownOpen Processing payments at scale—payroll, merchant payouts, loyalty rewards—requires more than sending individual transfers. To process many payments efficiently: 1. **Batch instructions** into single transactions to reduce fees and latency 2. **Batch transactions** to parallelize throughput across the network 3. **Fee abstraction** so users never need to hold SOL [### Batch Payments\ \ Send tokens to multiple recipients in a single transaction.](https://solana.com/docs/payments/send-payments/payment-processing/batch-payments) [### Fee Abstraction\ \ Abstract fees so users never need to hold SOL.](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction) Is this page helpful? [Previous\ \ Payment with Memo](https://solana.com/docs/payments/send-payments/payment-with-memo) [Next\ \ Batch Payments](https://solana.com/docs/payments/send-payments/payment-processing/batch-payments) ### Table of Contents No Headings [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/send-payments/payment-processing/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Payment Processing | Solana --- # Verifying Programs | Solana [Solana Documentation](https://solana.com/docs) Developing Programs [Verifying Programs](https://solana.com/docs/programs/verified-builds) ======================================================================= Copy MarkdownOpen This guide is meant to be a reference for developers who want to implement verified builds for their programs on Solana. We will cover what verified builds are, how to use them, special considerations, and best practices to ensure the authenticity of your program onchain. [What are verified builds?](https://solana.com/docs/programs/verified-builds#what-are-verified-builds) ======================================================================================================= Verified builds ensure that the executable program you deploy to Solana’s network matches the source code in your repository. By doing this, developers and users can have confidence that the program running onchain corresponds exactly to the public codebase, promoting transparency and security. The verification process involves comparing the hash of the onchain program with the hash of the locally built program from the source code. This ensures no discrepancies between the two versions. > While a verified build should not be considered more secure than an unverified build, the build enables developers to self verify the source code matches what is deployed onchain. Using the source code, a developer can then validate what the code executes when sending a transaction. The verified builds pipeline was thought out and is maintained by [Ellipsis Labs](https://ellipsislabs.xyz/) and [OtterSec](https://osec.io/) . For more details, follow the guide in the [original verified builds](https://github.com/Ellipsis-Labs/solana-verifiable-build) repository as well and the verify build process directly into the [Anza](https://www.anza.xyz/) tool suite, once supported there. [How does it work?](https://solana.com/docs/programs/verified-builds#how-does-it-work) ======================================================================================= The verification process is done by comparing the hash of the onchain program with the hash of the locally built program from the source code. You build your program in a controlled environment using the Solana Verify CLI and Docker. This ensures that the build process is deterministic and consistent across different systems. Once you have the executable, you can deploy it to the Solana network. During the build process a [PDA](https://explorer.solana.com/address/63XDCHrwZu3mXsw2RUFb4tbNpChuUHx4eA5aJMnHkpQQ/anchor-account) of the [verify program](https://github.com/otter-sec/otter-verify) will be created. This PDA contains all the data necessary to verify the program. The PDA contains the program address, git url, commit hash and the arguments used to build the program. Using the data in the PDA everyone can run the verify program command locally and check if the program was built from the provided source code. Then everyone can verify for themselves completely trustlessly or can run their own [verify API](https://github.com/otter-sec/solana-verified-programs-api) maintained by [OtterSec](https://github.com/otter-sec) to provide an easy access point for users to check the verification. You can already see these [API calls](https://verify.osec.io/status/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY) being used in the [Solana Explorer](https://explorer.solana.com/address/E1fcPKuV1UJEsTJPpab2Jr8y87ZN73i4CHTPLbWQE6CA/verified-build) and [SolanaFM](https://solana.fm/address/E1fcPKuV1UJEsTJPpab2Jr8y87ZN73i4CHTPLbWQE6CA/transactions?cluster=mainnet-alpha) , among other places. [Why should I use verified builds?](https://solana.com/docs/programs/verified-builds#why-should-i-use-verified-builds) ======================================================================================================================= Using verified builds provides the following benefits: * Security: Guarantee that the program running onchain matches the source code, preventing malicious alterations. * Transparency: Allows other users and developers to validate that the onchain program is trustworthy by comparing it with the public codebase. * Trust: Increase user confidence, as verified builds demonstrate that your program's onchain behavior is aligned with your public code. When building verifiable programs, you minimize risks associated with running unauthorized or malicious code. It also ensures you comply with best practices and give security researchers an easy way to contact you. Also wallets and other tools can allow transactions from your program more easily as long as it is verified. * Discoverability: When you provide a verified build of you program everyone can find your source code, docs, program SDK or IDL and they can also easily contact you via github in case there is an issue. [How do I create verified builds?](https://solana.com/docs/programs/verified-builds#how-do-i-create-verified-builds) ===================================================================================================================== To create verified builds, you'll need to follow these steps: Summary: * Commit your code to a public repository * Build a verified build in docker * Deploy the verified build * Verify the deployed program against public API If you verify your program which is not build in a docker container it will most likely fail because Solana program builds are not deterministic across different systems. ### [Install Docker and Cargo](https://solana.com/docs/programs/verified-builds#install-docker-and-cargo) Install the necessary tools ensure you have Docker and Cargo installed. Docker provides a controlled build environment to ensure consistency, and Cargo is used for managing Rust packages. * Docker: Follow the steps on the [Docker website](https://docs.docker.com/engine/install/) to install Docker for your platform. Once installed, ensure the Docker service is running following this guide further. * Cargo: If you don’t already have Cargo installed, you can install it by running the following command: curl \--proto '=https' \--tlsv1.2 -sSf https://sh.rustup.rs | sh ### [Install the Solana Verify CLI](https://solana.com/docs/programs/verified-builds#install-the-solana-verify-cli) The Solana Verify CLI is the primary tool used to verify builds. Solana Verify CLI is currently maintained by [Ellipsis Labs](https://ellipsislabs.xyz/) and can be installed using Cargo. You can install it by running: cargo install solana-verify If you need a specific version of the CLI, you can pin the version with: cargo install solana-verify \--version $VERSION If desired, you can install a version directly from a specific commit: cargo install solana-verify \--git https://github.com/Ellipsis-Labs/solana-verifiable-build \--rev 13a1db2 ### [Prepare project](https://solana.com/docs/programs/verified-builds#prepare-project) To verify against a repository it needs to have a `Cargo.lock` file in the root directory of your repository. If you only have one program in your repository and a `cargo.lock` file in your root you can directly go to the next step and build your program. If your program is in a subfolder and you have a rust workspace you need to create a workspace `Cargo.toml` file in the root directory of your repository. You can use this `Cargo.toml` example as a preset: Cargo.toml \[workspace\] members = \["program/programs/\*"\] resolver = "2" \[profile.release\] overflow-checks = true lto = "fat" codegen-units = 1 \[profile.release.build-override\] opt-level = 3 incremental = false codegen-units = 1 Make sure that your program is in the `workspace/members` array and that the `Cargo.toml` of your program has the correct `lib` name configured. > Important is the `lib name` not the package name! Something like this: waffle/Cargo.toml \[package\] name = "waffle" version = "0.1.0" edition = "2021" \[lib\] name = "waffle" crate-type = \["cdylib", "lib"\] \[dependencies\] solana-program = "2.1.0" In this [repository](https://github.com/solana-developers/verified-program) you can see an example of a workspace with a program in a subfolder. Notice also that when the program is in a subfolder you later need to add this folder as `--mount-path` to the `verify-from-repo` command. In this [repository](https://github.com/solana-developers/solana-game-preset) you can find an anchor example. In this [repository](https://github.com/solana-developers/verified-program-root) you can find a native rust example. With this `Cargo.toml` file in place you can then run `cargo generate-lockfile` to create a lock file and continue to building your program. ### [Building Verifiable Programs](https://solana.com/docs/programs/verified-builds#building-verifiable-programs) To verifiably build your Solana program, navigate to the directory containing your workspace's `Cargo.toml` file and run: solana-verify build This will copy your environment into a docker container and build it in a deterministic way. > Make sure that you actually deploy the verified build and don't accidentally overwrite it with `anchor build` or `cargo build-sbf` since these will most likely not result into the same hash and though your verification will fail. For projects with multiple programs, you can build a specific program by using the library name (not the package name): solana-verify build \--library-name $PROGRAM\_LIB\_NAME This process ensures deterministic builds and can take some time, especially on certain systems (e.g., M1 MacBook) because it is running within a docker container. For faster builds, using a Linux machine running x86 architecture is recommended. Once the build completes, you can retrieve the hash of the executable using the following command: solana-verify get-executable-hash target/deploy/$PROGRAM\_LIB\_NAME.so ### [Deploying Verifiable Programs](https://solana.com/docs/programs/verified-builds#deploying-verifiable-programs) Once you have built your program and retrieved its hash, you can deploy it to the Solana network. It is recommended to use a multi-signature or governance solution like [Squads Protocol](https://squads.so/protocol) for safe deployments, but you can also directly deploy with: solana program deploy \-u $NETWORK\_URL target/deploy/$PROGRAM\_LIB\_NAME.so \--program-id $PROGRAM\_ID \--with-compute-unit-price 50000 --max-sign-attempts 100 --use-rpc A currently fitting low priority fee you can request from your rpc provider for example [Quicknode](https://www.quicknode.com/gas-tracker/solana) . To verify the deployed program matches the built executable, run: solana-verify get-program-hash \-u $NETWORK\_URL $PROGRAM\_ID > You may have different versions deployed on different [Solana clusters](https://solana.com/docs/references/clusters) > (i.e. devnet, testnet, mainnet). Ensure you use the correct network URL for the desired Solana cluster you want to verify a program against. Remote verification will only work on mainnet. ### [Verifying against repositories](https://solana.com/docs/programs/verified-builds#verifying-against-repositories) To verify a program against its public repository, use: solana-verify verify-from-repo \-u $NETWORK\_URL \--program-id $PROGRAM\_ID https://github.com/$REPO\_PATH \--commit-hash $COMMIT\_HASH \--library-name $PROGRAM\_LIB\_NAME \--mount-path $MOUNT\_PATH > While you run the verified build in your program directory, when running `verify-from-repo` you need to add the `--mount-path` flag. This will be the path to the folder containing the `Cargo.toml` that contains your program's library name. This command compares the onchain program hash with the executable hash built from the source at the specified commit hash. At the end the command will ask you if you want to upload your verification data onchain. If you do that the Solana Explorer will immediately show your program's verification data. Until it was verified by a remote build it will show as unverified. Learn how you can verify your program against a public API in the next step. If you want to lock the verification to a certain release, you can append the `--commit-hash` flag to the command. ### [Verify against public API](https://solana.com/docs/programs/verified-builds#verify-against-public-api) Finally you can also directly verify the program against anyone that is running the verify API:: solana-verify verify-from-repo \--remote -um --program-id PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY https://github.com/Ellipsis-Labs/phoenix-v1 > It is recommended to use a payed RPC Url because otherwise you may run into rate limits of the free RPCs. So instead of `-um` you should use `--url yourRpcUrl` for a more reliable verification. The `--remote` flag sends a build request to the OtterSec API, which triggers a remote build of your program. Once the build is complete, the system verifies that the onchain hash of your program matches the hash of the generated build artifact from your repository. The default is the [OtterSec API](https://github.com/otter-sec/solana-verified-programs-api) . Make sure to pick yes when you are asked to upload the verification data onchain. This is used by the API to verify that you uploaded the verification data. You can also trigger a remote job manually by using: solana-verify remote submit-job \--program-id \--uploader Where the uploader is the address that has the authority to write to the PDA. That should be program authority in most cases. If your program is controlled by a multisig please continue in the [multisig verification](https://solana.com/docs/programs/verified-builds#how-to-verify-your-program-when-its-controlled-by-a-multisig-like-squads) part of this guide below. This will submit a job to the OtterSec API and you can then verify the job status with: solana-verify remote get-job-status \--job-id Once the verification has completed successfully, which may take awhile, you will be able to see your program as verified in the [OtterSec API for single programs](https://verify.osec.io/status/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY) and in the [Solana Explorer](https://explorer.solana.com/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY/verified-build) , [SolanaFM](https://solana.fm/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY?cluster=mainnet-alpha) , [SolScan](https://solscan.io/account/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY#programVerification) and eventually also on the community-run website [SolanaVerify.org](https://www.solanaverify.org/) maintained by [0xDeep](https://x.com/0xDeep) and the [OtterSec verified programs API](https://verify.osec.io/verified-programs) and at last in the [Verified Programs Dune Dashboard](https://dune.com/jonashahn/verified-programs/dedf21e1-9b71-42c8-89f9-02ed94628657) contributing to a more healthy Solana ecosystem. [How to verify your program when its controlled by a Multisig like Squads](https://solana.com/docs/programs/verified-builds#how-to-verify-your-program-when-its-controlled-by-a-multisig-like-squads) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ For the remote verification to work you need to write the verification data into a PDA signed by the program authority. If your program is controlled by a multisig you can export this write PDA transaction and submit it through [Squads Protocol](https://squads.so/protocol) or another multisig solution of your choice. ### [1\. Build the verifiable program](https://solana.com/docs/programs/verified-builds#1-build-the-verifiable-program) First build the program: solana-verify build This will build a verifiable build using a docker container using the solana version specified in the `Cargo.lock` file. ### [2\. Deploy the program](https://solana.com/docs/programs/verified-builds#2-deploy-the-program) solana config set \--url "PayedMainnetRPCAddress" // the public endpoint will be rate limited too much solana program deploy target/deploy/verify\_squads.so For the rest of this multisig guide, we will use an example program ID of `6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD`. ### [3\. Commit and verify against repository](https://solana.com/docs/programs/verified-builds#3-commit-and-verify-against-repository) Once that is done we commit the project to to github. Here is an example: [https://github.com/solana-developers/verify-squads](https://github.com/solana-developers/verify-squads) Optional: See if you can verify locally first (this command uses example program ID `6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD`): solana-verify verify-from-repo https://github.com/solana-developers/verify-squads \--program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD Just to make sure your parameters are correct. ### [4\. Transfer program authority to multisig](https://solana.com/docs/programs/verified-builds#4-transfer-program-authority-to-multisig) If you have not yet transfer your programs authority to the multisig and copy the multisig authority. You need it in the next step. ### [5\. Export PDA transaction](https://solana.com/docs/programs/verified-builds#5-export-pda-transaction) When you have you program authority locally you are prompted to upload the build data onchain when using the command `solana-verify verify-from-repo`. Since you can not do that when you are using a multisig you need to export the PDA transaction manually and then trigger the transaction through Squads. solana-verify export-pda-tx https://github.com/solana-developers/verify-squads \--program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD \--uploader \--encoding base58 \--compute-unit-price 0 This will return you a base58 transaction. If you want a base64 encoded transaction for use in a transaction inspector, you can use `--encoding base64`. P6vBfcPaaXb8fZoT3NBAYEcdtEj7tubA1k2gBxmFKZ3UWF5YyrmDMFTvLKALCJoUuRsPAjMckudYruCu3eeWQtuDrFbEMLxLFutnKXac974fnkMivcwUdY66VLjbxQT6ATmcy7F4hBtz1G4P1h6iBJLhb8WtrtgY3i4qq45MUEb7RjuMEfUFXKrNgPdGxkz5xvMHq3dxKRcpmEK5k2DkeW6SUQYBVe19Ga3B9GyhTX8k3CMt9JCEah13WyRnQd8GjoK6sTEvGJym6xDNvmd8yiJYSNcaYwEJsjHEUf4Yh6kAC7ki2KRvVAr3NVe1gjqK9McrwSQjtUatvydTG8Zovcr7PPUEMf3yPMgKXjZLB2QpkH63yTTYdNAnWFuv9E6b6nYRqye5XcNi436yKw5U14fXh65yK34bgYLi9328UT1huJELsJU9BRGnGUmb6GWp6c2WL5BhnzgNTSnt9TXFfEgUMzhvKzpVBxLP44hwqqBdyUhHFysCF37531PnmiESq8x1xou23xJ6FcQbc199754MkqQd7tX9CUznGzAEqHGkzn3VBoJnojsKtgYmiTYbdRsT1CU18MbYEE7WvGAvXyxxbpNzbAcc94HrnM6cqRGmwhEBroPfFghTdmzg9D ### [6\. Submit transaction through Squads](https://solana.com/docs/programs/verified-builds#6-submit-transaction-through-squads) Go to the squads transaction builder and import the base58 encoded transaction. Make sure that in the simulation the transaction only has a call to the osec verify program and the computer budget program and nothing else! ### [7\. Submit remote verification job](https://solana.com/docs/programs/verified-builds#7-submit-remote-verification-job) Once the transaction to squads was successful you can submit the remote job: solana-verify remote submit-job \--program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD \--uploader This is it! You have verified your program against a public repository and submitted a remote job to the OtterSec API. You should be able to see it reflect in the solana explorer and other places now. ### [8\. Updating the program (Optional)](https://solana.com/docs/programs/verified-builds#8-updating-the-program-optional) When you update your program you need to export a new PDA transaction and submit it through Squads again. Doing an update to the program: solana-verify build solana program write-buffer target/deploy/verify\_squads.so \--with-compute-unit-price 50000 --max-sign-attempts 50 Then transfer that buffer authority to the multisig or directly create the buffer with the authority of the multisig. solana program set-buffer-authority Fu3k79g53ZozAj47uq1tXrFy4QbQYh7y745DDsxjtyLR \--new-buffer-authority 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K ### [9\. Export and submit new PDA transaction](https://solana.com/docs/programs/verified-builds#9-export-and-submit-new-pda-transaction) Don't forget to commit your changes to github. Export the PDA upgrade transaction again: solana-verify export-pda-tx https://github.com/solana-developers/verify-squads \--program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD \--uploader 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K Submit the transaction through Squads again. You can see an example transaction [here](https://solana.fm/tx/4zJ1vK2KToAwxuEYzTMLqPkcebjoi9rdeeyxtEEx9L5Q4vWDA8h6Rr4kPRuRxcV7ZLKMr6qx1LTWb6x3ZpUJaFUW?cluster=mainnet-alpha) . Then submit for another remote build: solana-verify remote submit-job \--program-id 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD \--uploader 3JG6ULvZVCrkKtSSskKNJGe8RNZGFe8Ruev9KUhxzK5K Should result in something like this: Verification request sent with request id: b63339d2-163e-49ac-b55d-3454c1c2b5b3 Verification in progress... ⏳ \[00:18:02\] ✅ Process completed. (Done in 18 minutes) Program 6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD has been verified. ✅ The provided GitHub build matches the on-chain hash. On Chain Hash: 96f8c3d9400258f7759408d1f6f8435b4a24d9b52f5a0340d97907e567cb8773 Executable Hash: 96f8c3d9400258f7759408d1f6f8435b4a24d9b52f5a0340d97907e567cb8773 Repo URL: https://github.com/Woody4618/verify-squads/tree/0fb0a2e30c15c51732c0ad5e837975a6f7bbc7ed Check the verification status at: https://verify.osec.io/status/6XBGfP17P3KQAKoJb2s5M5fR4aFTXzPeuC1af2GYkvhD Job url: https://verify.osec.io/job/b63339d2-163e-49ac-b55d-3454c1c2b5b3 Congratulations you have verified your program after a multisig upgrade! [Verify from docker image](https://solana.com/docs/programs/verified-builds#verify-from-docker-image) ------------------------------------------------------------------------------------------------------ You can also verify your program against a docker image by running the following command: solana-verify verify-from-image \-e examples/hello\_world/target/deploy/hello\_world.so \-i ellipsislabs/hello\_world\_verifiable\_build:latest \-p 2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn This command loads up the image stored at `ellipsislabs/hello_world_verifiable_build:latest`, and verifies that the hash of the executable path in the container is the same as the hash of the on-chain program supplied to the command. Because the build was already uploaded to an image, there is no need for a full rebuild of the executable which can take a long time. The Dockerfile that creates the image `ellipsislabs/hello_world_verifiable_build:latest` can be found in the ellipsis labs repository [/examples/hello\_world](https://github.com/Ellipsis-Labs/solana-verifiable-build/tree/master/examples/hello_world) . Below is the expected output: Verifying image: "ellipsislabs/hello\_world\_verifiable\_build:latest", on network "https://api.mainnet.solana.com" against program ID 2ZrriTQSVekoj414Ynysd48jyn4AX6ZF4TTJRqHfbJfn Executable path in container: "examples/hello\_world/target/deploy/hello\_world.so" Executable hash: 08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760 Program hash: 08d91368d349c2b56c712422f6d274a1e8f1946ff2ecd1dc3efc3ebace52a760 Executable matches on-chain program data ✅ [Example verified build](https://solana.com/docs/programs/verified-builds#example-verified-build) -------------------------------------------------------------------------------------------------- Here’s an example of verifying an example program with the ID `FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv` using the source code from this [repository](https://github.com/solana-developers/verified-program) : solana-verify verify-from-repo https://github.com/solana-developers/verified-program \--url YOUR-RPC-URL \--program-id FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv \--mount-path waffle \--library-name waffle \--commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e By default the `verify-from-repo` command takes the last commit on the main branch. You can also define a certain commit in case you want to continue working on the repository by using the `commit-hash` parameter: `--commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e` Finally you can also directly verify the program against the OtterSec API: solana-verify verify-from-repo https://github.com/solana-developers/verified-program \--url YOUR-RPC-URL \--remote --program-id FWEYpBAf9WsemQiNbAewhyESfR38GBBHLrCaU3MpEKWv \--mount-path waffle \--library-name waffle \--commit-hash 5b82b86f02afbde330dff3e1847bed2d42069f4e The `--remote` command sends a build request to the OtterSec API, which triggers a remote build of your program. Once the build is complete, the system verifies that the onchain hash of your program matches the hash of the generated build artifact from your repository. [Popular programs that are already verified](https://solana.com/docs/programs/verified-builds#popular-programs-that-are-already-verified) ------------------------------------------------------------------------------------------------------------------------------------------ ### [Phoenix](https://solana.com/docs/programs/verified-builds#phoenix) solana-verify verify-from-repo \-um --program-id PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY https://github.com/Ellipsis-Labs/phoenix-v1 Final Output: Executable Program Hash from repo: 6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9 On-chain Program Hash: 6877a5b732b3494b828a324ec846d526d962223959534dbaf4209e0da3b2d6a9 Program hash matches ✅ ### [Squads V3](https://solana.com/docs/programs/verified-builds#squads-v3) solana-verify verify-from-repo https://github.com/Squads-Protocol/squads-mpl \--commit-hash c95b7673d616c377a349ca424261872dfcf8b19d \--program-id SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu \-um --library-name squads\_mpl \--bpf > Notice we needed to specify the `library-name` because the Squads repo includes multiple programs. We use the `--bpf` flag because `squads_mpl` was previously verified with Anchor. Final Output: Executable Program Hash from repo: 72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205c On-chain Program Hash: 72da599d9ee14b2a03a23ccfa6f06d53eea4a00825ad2191929cbd78fb69205c Program hash matches ✅ ### [Drift V2](https://solana.com/docs/programs/verified-builds#drift-v2) solana-verify verify-from-repo \-um --program-id dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH https://github.com/drift-labs/protocol-v2 \--commit-hash 110d3ff4f8ba07c178d69f9bfc7b30194fac56d6 \--library-name drift Final Output: Executable Program Hash from repo: e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828 On-chain Program Hash: e31d58edeabc3c30bf6f2aa60bfaa5e492b41ec203e9006404b463e5adee5828 Program hash matches ✅ ### [Marginfi V2](https://solana.com/docs/programs/verified-builds#marginfi-v2) solana-verify verify-from-repo \-um --program-id MFv2hWf31Z9kbCa1snEPYctwafyhdvnV7FZnsebVacA https://github.com/mrgnlabs/marginfi-v2 \--commit-hash d33e649e415c354cc2a1e3c49131725552d69ba0 \--library-name marginfi \-- --features mainnet-beta Final Output: Executable Program Hash from repo: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5 On-chain Program Hash: 890d68f48f96991016222b1fcbc2cc81b8ef2dcbf280c44fe378c523c108fad5 Program hash matches ✅ [Conclusion](https://solana.com/docs/programs/verified-builds#conclusion) ========================================================================== Using [verified builds on Solana](https://solana.com/developers/guides/advanced/verified-builds) ensures the integrity and trustworthiness of your programs on the network and allow developers to find your SDKs directly from a Solana Explorer. By leveraging tools like the Solana Verify CLI and Docker, you can maintain verifiable and secure builds that align with your source code. Always take the necessary precautions to use consistent environments, and consider governance solutions for safe upgrades and deployments. [Security + Disclaimer](https://solana.com/docs/programs/verified-builds#security--disclaimer) ----------------------------------------------------------------------------------------------- While verified builds are a powerful tool for ensuring the integrity of your Solana programs it is not completely trustless in the default setup. The docker images are built and hosted by the Solana Foundation. Be aware that you are building your project in a downloaded docker image and that your whole setup gets copied into that docker image for building including potentially sensitive information. If you want to have a completely trustless setup you can build the docker images yourself and host them on your own infrastructure. This way you can be sure that the docker images are not tampered with. You can find the scripts to create your own docker images in the [Verified builds repository](https://github.com/Ellipsis-Labs/solana-verifiable-build) and you can fork it and run the github actions yourself or validate that they are correct. Furthermore for the remote verification you are trusting the OtterSec API and the [Solana Explorer](https://explorer.solana.com/address/PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY) to a certain degree. The API or Solana Explorer may potentially display incorrect information if compromised. If you want to have a completely trustless setup you can run the [Verify API](https://github.com/otter-sec/solana-verified-programs-api) yourself or run the program verification locally yourself using the `verify-from-repo` command using the on chain verify data that is saved in a [PDA](https://explorer.solana.com/address/63XDCHrwZu3mXsw2RUFb4tbNpChuUHx4eA5aJMnHkpQQ/anchor-account) that is derived from the programs deploy authority and the [verify program](https://explorer.solana.com/address/verifycLy8mB96wd9wqq3WDXQwM4oU6r42Th37Db9fC) . The verify program is deployed by the [OtterSec team](https://osec.io/) and is not yet frozen so it can be upgraded at any time. The Solana Foundation, OtterSec and the Ellipsis Labs team are not responsible for any losses or damages that may occur from using the verified builds pipeline. [Security.txt for Solana programs](https://solana.com/docs/programs/verified-builds#securitytxt-for-solana-programs) ===================================================================================================================== In addition to verified builds you can also add a `security.txt` file to your program. In the future, once implemented, the `security.txt` will hold the verifier public key for easy access to the verification data stored in the verification PDA. The PDA containing all the information needed to build and verify a program is derived from the programs address and the verifier pubkey. By default this is the same pubkey that built and deployed the program. But it can also be another pubkey that can be specified in the `security.txt`. The `security.txt` feature allows developers to embed contact and security information directly within their Solana smart contracts. Inspired by [securitytxt.org](https://securitytxt.org/) , this approach provides a standardized way for security researchers to reach out to project maintainers, even if they only know the contract's address. [Why use security.txt?](https://solana.com/docs/programs/verified-builds#why-use-securitytxt) ---------------------------------------------------------------------------------------------- For many projects, especially smaller or private ones, identifying the developers from just the contract address can be difficult and time-consuming. Embedding a `security.txt` file within the program ensures that security researchers can easily contact the correct people, potentially preventing exploits and ensuring timely bug reports. [How to implement security.txt](https://solana.com/docs/programs/verified-builds#how-to-implement-securitytxt) --------------------------------------------------------------------------------------------------------------- To add a `security.txt` to your Solana program, include the following steps: Add the `solana-security-txt` dependency to your `Cargo.toml`: Cargo.toml \[dependencies\] solana-security-txt = "1.1.1" Use the `security_txt!` macro in your contract to define your security information. You can include contact details, project URLs, and even a security policy. Here's an example: #\[cfg(not(feature \= "no-entrypoint"))\] use {default\_env::default\_env, solana\_security\_txt::security\_txt}; #\[cfg(not(feature \= "no-entrypoint"))\] security\_txt! { name: "MyProject", project\_url: "https://myproject.com", contacts: "email:security@myproject.com,discord:security#1234", policy: "https://myproject.com/security-policy", // Optional Fields preferred\_languages: "en,de", source\_code: "https://github.com/solana-developers/solana-game-preset", source\_revision: "5vJwnLeyjV8uNJSp1zn7VLW8GwiQbcsQbGaVSwRmkE4r", source\_release: "", encryption: "", auditors: "Verifier pubkey: 5vJwnLeyjV8uNJSp1zn7VLW8GwiQbcsQbGaVSwRmkE4r", acknowledgements: "Thank you to our bug bounty hunters!" } Once the `security.txt` information is embedded in your program, it can be easily queried via tools like the Solana Explorer, ensuring that your contact and security details are available to anyone looking to report potential issues. [Best practices](https://solana.com/docs/programs/verified-builds#best-practices) ---------------------------------------------------------------------------------- * Use Links: For information likely to change (e.g., contact details), it's recommended to link to a web page rather than hard-coding them into the contract. This avoids the need for frequent program upgrades. * Verification: Before deploying, verify the format and content using the `query-security-txt` tool, which can validate both onchain programs and local binaries: query-security-txt target/bpfel-unknown-unknown/release/my\_contract.so By embedding security contact information directly into your contract, you make it easier for researchers to reach you, fostering better security and communication within the Solana ecosystem. This is [an example of how security.txt looks in the Solana Explorer](https://explorer.solana.com/address/HPxKXnBN4vJ8RjpdqDCU7gvNQHeeyGnSviYTJ4fBrDt4/security?cluster=devnet) The `security.txt` project is maintained by [Neodyme Labs](https://github.com/neodyme-labs) Is this page helpful? [Previous\ \ Generating Clients](https://solana.com/docs/programs/codama/clients) [Next\ \ Program Examples](https://solana.com/docs/programs/examples) ### Table of Contents [What are verified builds?](https://solana.com/docs/programs/verified-builds#what-are-verified-builds) [How does it work?](https://solana.com/docs/programs/verified-builds#how-does-it-work) [Why should I use verified builds?](https://solana.com/docs/programs/verified-builds#why-should-i-use-verified-builds) [How do I create verified builds?](https://solana.com/docs/programs/verified-builds#how-do-i-create-verified-builds) [Install Docker and Cargo](https://solana.com/docs/programs/verified-builds#install-docker-and-cargo) [Install the Solana Verify CLI](https://solana.com/docs/programs/verified-builds#install-the-solana-verify-cli) [Prepare project](https://solana.com/docs/programs/verified-builds#prepare-project) [Building Verifiable Programs](https://solana.com/docs/programs/verified-builds#building-verifiable-programs) [Deploying Verifiable Programs](https://solana.com/docs/programs/verified-builds#deploying-verifiable-programs) [Verifying against repositories](https://solana.com/docs/programs/verified-builds#verifying-against-repositories) [Verify against public API](https://solana.com/docs/programs/verified-builds#verify-against-public-api) [How to verify your program when its controlled by a Multisig like Squads](https://solana.com/docs/programs/verified-builds#how-to-verify-your-program-when-its-controlled-by-a-multisig-like-squads) [1\. Build the verifiable program](https://solana.com/docs/programs/verified-builds#1-build-the-verifiable-program) [2\. Deploy the program](https://solana.com/docs/programs/verified-builds#2-deploy-the-program) [3\. Commit and verify against repository](https://solana.com/docs/programs/verified-builds#3-commit-and-verify-against-repository) [4\. Transfer program authority to multisig](https://solana.com/docs/programs/verified-builds#4-transfer-program-authority-to-multisig) [5\. Export PDA transaction](https://solana.com/docs/programs/verified-builds#5-export-pda-transaction) [6\. Submit transaction through Squads](https://solana.com/docs/programs/verified-builds#6-submit-transaction-through-squads) [7\. Submit remote verification job](https://solana.com/docs/programs/verified-builds#7-submit-remote-verification-job) [8\. Updating the program (Optional)](https://solana.com/docs/programs/verified-builds#8-updating-the-program-optional) [9\. Export and submit new PDA transaction](https://solana.com/docs/programs/verified-builds#9-export-and-submit-new-pda-transaction) [Verify from docker image](https://solana.com/docs/programs/verified-builds#verify-from-docker-image) [Example verified build](https://solana.com/docs/programs/verified-builds#example-verified-build) [Popular programs that are already verified](https://solana.com/docs/programs/verified-builds#popular-programs-that-are-already-verified) [Phoenix](https://solana.com/docs/programs/verified-builds#phoenix) [Squads V3](https://solana.com/docs/programs/verified-builds#squads-v3) [Drift V2](https://solana.com/docs/programs/verified-builds#drift-v2) [Marginfi V2](https://solana.com/docs/programs/verified-builds#marginfi-v2) [Conclusion](https://solana.com/docs/programs/verified-builds#conclusion) [Security + Disclaimer](https://solana.com/docs/programs/verified-builds#security--disclaimer) [Security.txt for Solana programs](https://solana.com/docs/programs/verified-builds#securitytxt-for-solana-programs) [Why use security.txt?](https://solana.com/docs/programs/verified-builds#why-use-securitytxt) [How to implement security.txt](https://solana.com/docs/programs/verified-builds#how-to-implement-securitytxt) [Best practices](https://solana.com/docs/programs/verified-builds#best-practices) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/programs/verified-builds.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Payment with Memo | Solana [Payments](https://solana.com/docs) [Send Payments](https://solana.com/docs/payments/send-payments) [Payment with Memo](https://solana.com/docs/payments/send-payments/payment-with-memo) ====================================================================================== Copy MarkdownOpen Solana's memo program lets you attach invoice numbers, order IDs, or custom references to any payment. These memos are permanently recorded on-chain and visible in transaction logs, making it easy to match payments to your internal systems. [How It Works](https://solana.com/docs/payments/send-payments/payment-with-memo#how-it-works) ---------------------------------------------------------------------------------------------- The Memo program writes text to the transaction's logs. These logs are indexed by explorers and RPC providers, making memos searchable for payment reconciliation. See [How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) for core payment concepts. Adding a memo requires building instructions directly, which gives you control over what's included in the transaction. The steps below show the core flow. See the [Demo](https://solana.com/docs/payments/send-payments/payment-with-memo#demo) for complete runnable code. Import Memo Program ------------------- Import `getAddMemoInstruction` from `@solana-program/memo` to create memo instructions. Payment with Memo import { getAddMemoInstruction } from "@solana-program/memo"; Create Transfer Instruction --------------------------- Create the token transfer instruction specifying the source ATA, destination ATA, authority (signer), and amount in base units. Payment with Memo import { getAddMemoInstruction } from "@solana-program/memo"; const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender.address, amount: 250\_000n // adjusted for the mint's decimals }); Create Memo Instruction ----------------------- Create a memo instruction with a message. This message will be visible in the program logs of the transaction. Payment with Memo import { getAddMemoInstruction } from "@solana-program/memo"; const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender.address, amount: 250\_000n }); const memoInstruction \= getAddMemoInstruction({ memo: "Payment for services rendered - Invoice #12345" }); Send Transaction with Memo -------------------------- Combine the transfer and memo instructions in a single transaction. Payment with Memo import { getAddMemoInstruction } from "@solana-program/memo"; const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender.address, amount: 250\_000n }); const memoInstruction \= getAddMemoInstruction({ memo: "Payment for services rendered - Invoice #12345" }); const signature \= await client.transaction.prepareAndSend({ authority: sender, instructions: \[transferInstruction, memoInstruction\], version: 0 }); View Memo in Transaction Logs ----------------------------- After the transaction confirms, fetch it to view the memo in the logs. The memo appears as a log message from the Memo program. Payment with Memo import { getAddMemoInstruction } from "@solana-program/memo"; const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender.address, amount: 250\_000n }); const memoInstruction \= getAddMemoInstruction({ memo: "Payment for services rendered - Invoice #12345" }); const signature \= await client.transaction.prepareAndSend({ authority: sender, instructions: \[transferInstruction, memoInstruction\], version: 0 }); const transaction \= await client.runtime.rpc .getTransaction(signature, { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }) .send(); console.log("Transaction logs with Memo:"); console.log(transaction?.meta?.logMessages); Example Transaction Logs "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke \[1\]", "Program log: Instruction: Transfer", "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1682 of 200000 compute units", "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success", "Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr invoke \[1\]", 'Program log: Memo (len 46): "Payment for services rendered - Invoice #12345"', "Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr consumed 18097 of 198318 compute units", "Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr success", "Program ComputeBudget111111111111111111111111111111 invoke \[1\]", "Program ComputeBudget111111111111111111111111111111 success" Import Memo Program ------------------- Import `getAddMemoInstruction` from `@solana-program/memo` to create memo instructions. Create Transfer Instruction --------------------------- Create the token transfer instruction specifying the source ATA, destination ATA, authority (signer), and amount in base units. Create Memo Instruction ----------------------- Create a memo instruction with a message. This message will be visible in the program logs of the transaction. Send Transaction with Memo -------------------------- Combine the transfer and memo instructions in a single transaction. View Memo in Transaction Logs ----------------------------- After the transaction confirms, fetch it to view the memo in the logs. The memo appears as a log message from the Memo program. Example Transaction Logs "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb invoke \[1\]", "Program log: Instruction: Transfer", "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb consumed 1682 of 200000 compute units", "Program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb success", "Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr invoke \[1\]", 'Program log: Memo (len 46): "Payment for services rendered - Invoice #12345"', "Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr consumed 18097 of 198318 compute units", "Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr success", "Program ComputeBudget111111111111111111111111111111 invoke \[1\]", "Program ComputeBudget111111111111111111111111111111 success" Payment with Memo import { getAddMemoInstruction } from "@solana-program/memo"; ### [Demo](https://solana.com/docs/payments/send-payments/payment-with-memo#demo) Demo // Click ">" icon on left to expand demo imports // Generate keypairs for sender and recipient const sender \= (await generateKeypair()).signer; const recipient \= (await generateKeypair()).signer; console.log("Sender Address:", sender.address); console.log("Recipient Address:", recipient.address); // Demo Setup: Create client, mint account, token accounts, and fund with initial tokens const { client, mint } \= await demoSetup(sender, recipient); console.log("\\nMint Address:", mint.address); // Derive the Associated Token Accounts addresses (ATAs) for sender and recipient const \[senderAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: sender.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); const \[recipientAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: recipient.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); console.log("Sender Token Account:", senderAta.toString()); console.log("Recipient Token Account:", recipientAta.toString()); // ============================================================================= // Token Payment with Memo Demo // ============================================================================= // Create instruction to transfer tokens from sender to recipient // Transferring 250,000 base units = 0.25 tokens (with 6 decimals) const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender.address, amount: 250\_000n // 0.25 tokens }); // Create instruction to add a memo to the transaction const memoInstruction \= getAddMemoInstruction({ memo: "Payment for services rendered - Invoice #12345" }); // Prepare and send transaction with both transfer and memo using @solana/client const signature \= await client.transaction.prepareAndSend({ authority: sender, instructions: \[transferInstruction, memoInstruction\], version: 0 }); console.log("\\n\=== Token Payment with Memo Complete ==="); console.log("Transaction Signature:", signature.toString()); // Fetch final token account balances using @solana/client SPL token helper const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); console.log("\\nSender Token Account Balance:", senderBalance); console.log("Recipient Token Account Balance:", recipientBalance); // Fetch transaction details to view the memo in the logs const transaction \= await client.runtime.rpc .getTransaction(signature, { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }) .send(); console.log("\\nTransaction logs with Memo:"); console.log(transaction?.meta?.logMessages); // ============================================================================= // Demo Setup Helper Function // ============================================================================= Console RunClick to execute the code. Demo // Click ">" icon on left to expand demo imports // Generate keypairs for sender and recipient const sender \= (await generateKeypair()).signer; const recipient \= (await generateKeypair()).signer; console.log("Sender Address:", sender.address); console.log("Recipient Address:", recipient.address); // Demo Setup: Create client, mint account, token accounts, and fund with initial tokens const { client, mint } \= await demoSetup(sender, recipient); console.log("\\nMint Address:", mint.address); // Derive the Associated Token Accounts addresses (ATAs) for sender and recipient const \[senderAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: sender.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); const \[recipientAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: recipient.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); console.log("Sender Token Account:", senderAta.toString()); console.log("Recipient Token Account:", recipientAta.toString()); // ============================================================================= // Token Payment with Memo Demo // ============================================================================= // Create instruction to transfer tokens from sender to recipient // Transferring 250,000 base units = 0.25 tokens (with 6 decimals) const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender.address, amount: 250\_000n // 0.25 tokens }); // Create instruction to add a memo to the transaction const memoInstruction \= getAddMemoInstruction({ memo: "Payment for services rendered - Invoice #12345" }); // Prepare and send transaction with both transfer and memo using @solana/client const signature \= await client.transaction.prepareAndSend({ authority: sender, instructions: \[transferInstruction, memoInstruction\], version: 0 }); console.log("\\n\=== Token Payment with Memo Complete ==="); console.log("Transaction Signature:", signature.toString()); // Fetch final token account balances using @solana/client SPL token helper const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); console.log("\\nSender Token Account Balance:", senderBalance); console.log("Recipient Token Account Balance:", recipientBalance); // Fetch transaction details to view the memo in the logs const transaction \= await client.runtime.rpc .getTransaction(signature, { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }) .send(); console.log("\\nTransaction logs with Memo:"); console.log(transaction?.meta?.logMessages); // ============================================================================= // Demo Setup Helper Function // ============================================================================= Console RunClick to execute the code. Is this page helpful? [Previous\ \ Basic Payment](https://solana.com/docs/payments/send-payments/basic-payment) [Next\ \ Payment Processing](https://solana.com/docs/payments/send-payments/payment-processing) ### Table of Contents [How It Works](https://solana.com/docs/payments/send-payments/payment-with-memo#how-it-works) [Demo](https://solana.com/docs/payments/send-payments/payment-with-memo#demo) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/send-payments/payment-with-memo.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # getTransaction RPC Method | Solana [Solana Documentation](https://solana.com/docs) [Solana RPC Methods](https://solana.com/docs/rpc) [HTTP Methods](https://solana.com/docs/rpc/http) [getTransaction RPC Method](https://solana.com/docs/rpc/http/gettransaction) ============================================================================= Copy MarkdownOpen Returns transaction details for a confirmed transaction #### params stringrequired Transaction signature, as base-58 encoded string objectoptional Configuration object containing the following fields: commitmentstring maxSupportedTransactionVersionnumber encodingstring #### result object | null Returns `null` if transaction is not found or not confirmed, otherwise returns an object containing: blockTimei64 | null metaobject | null slotu64 transactionobject | \[string,encoding\] version"legacy" | number | undefined cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getTransaction", \> "params": \[\ \ \> "4ReKprwf3WdLHRrzp4ctPWNBsQDPL3VZz3zMmoZfcGJMJCHh5Vq937mPdyxhCbw54wNnA6hZ7KfNpQdpt13yY7A9",\ \ \> {\ \ \> "commitment": "confirmed",\ \ \> "maxSupportedTransactionVersion": 0,\ \ \> "encoding": "json"\ \ \> }\ \ \> \] \> } \> ' Try it Response { "jsonrpc": "2.0", "result": { "blockTime": 1763747336, "meta": { "slot": 423108383, "transaction": { "version": "legacy" }, "id": 1 } cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getTransaction", \> "params": \[\ \ \> "4ReKprwf3WdLHRrzp4ctPWNBsQDPL3VZz3zMmoZfcGJMJCHh5Vq937mPdyxhCbw54wNnA6hZ7KfNpQdpt13yY7A9",\ \ \> {\ \ \> "commitment": "confirmed",\ \ \> "maxSupportedTransactionVersion": 0,\ \ \> "encoding": "json"\ \ \> }\ \ \> \] \> } \> ' Try it #### params stringrequired Transaction signature, as base-58 encoded string objectoptional Configuration object containing the following fields: commitmentstring maxSupportedTransactionVersionnumber encodingstring #### result Response { "jsonrpc": "2.0", "result": { "blockTime": 1763747336, "meta": { "slot": 423108383, "transaction": { "version": "legacy" }, "id": 1 } object | null Returns `null` if transaction is not found or not confirmed, otherwise returns an object containing: blockTimei64 | null metaobject | null slotu64 transactionobject | \[string,encoding\] version"legacy" | number | undefined [Example Results](https://solana.com/docs/rpc/http/gettransaction#example-results) ----------------------------------------------------------------------------------- The following examples show the responses for a transaction that creates an [associated token account](https://solana.com/docs/tokens/basics/create-token-account#how-to-create-an-associated-token-account) , presented for each supported `encoding` parameter. Json JsonParsed Base64 Base58 { "jsonrpc": "2.0", "result": { "blockTime": 1763751415, "meta": { "computeUnitsConsumed": 21889, "costUnits": 23273, "err": null, "fee": 5000, "innerInstructions": \[\ \ {\ \ "index": 0,\ \ "instructions": \[\ \ {\ \ "accounts": \[\ \ 3\ \ \],\ \ "data": "84eT",\ \ "programIdIndex": 5,\ \ "stackHeight": 2\ \ },\ \ {\ \ "accounts": \[\ \ 0,\ \ 1\ \ \],\ \ "data": "11119os1e9qSs2u7TsThXqkBSRVFxhmYaFKFZ1waB2X7armDmvK3p5GmLdUxYdg3h7QSrL",\ \ "programIdIndex": 2,\ \ "stackHeight": 2\ \ },\ \ {\ \ "accounts": \[\ \ 1\ \ \],\ \ "data": "P",\ \ "programIdIndex": 5,\ \ "stackHeight": 2\ \ },\ \ {\ \ "accounts": \[\ \ 1,\ \ 3\ \ \],\ \ "data": "6QFLvqUwxAjuz2HvEPJqmSbNyCeouS45dJEowLgrYTXLr",\ \ "programIdIndex": 5,\ \ "stackHeight": 2\ \ }\ \ \]\ \ }\ \ \], "loadedAddresses": { "readonly": \[\], "writable": \[\] }, "logMessages": \[\ \ "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL invoke \[1\]",\ \ "Program log: Create",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2\]",\ \ "Program log: Instruction: GetAccountDataSize",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1595 of 193103 compute units",\ \ "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",\ \ "Program 11111111111111111111111111111111 invoke \[2\]",\ \ "Program 11111111111111111111111111111111 success",\ \ "Program log: Initialize the associated token account",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2\]",\ \ "Program log: Instruction: InitializeImmutableOwner",\ \ "Program log: Please upgrade to SPL Token 2022 for immutable owner support",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1405 of 186490 compute units",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke \[2\]",\ \ "Program log: Instruction: InitializeAccount3",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4214 of 182608 compute units",\ \ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",\ \ "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL consumed 21889 of 200000 compute units",\ \ "Program ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL success"\ \ \], "postBalances": \[\ \ 996484120,\ \ 2039280,\ \ 1,\ \ 1461600,\ \ 933913600,\ \ 8468187701\ \ \], "postTokenBalances": \[\ \ {\ \ "accountIndex": 1,\ \ "mint": "5kR7n7QJv85NrwwXdYWZ52qkRcyvXqKWDPNooYcfDV6e",\ \ "owner": "47eFuHR9ste9kopiJ9eRxcwahmE62JovbKe5r7AjANut",\ \ "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",\ \ "uiTokenAmount": {\ \ "amount": "0",\ \ "decimals": 2,\ \ "uiAmount": null,\ \ "uiAmountString": "0"\ \ }\ \ }\ \ \], "preBalances": \[\ \ 998528400,\ \ 0,\ \ 1,\ \ 1461600,\ \ 933913600,\ \ 8468187701\ \ \], "preTokenBalances": \[\], "rewards": \[\], "status": { "Ok": null } }, "slot": 423118809, "transaction": { "message": { "accountKeys": \[\ \ "47eFuHR9ste9kopiJ9eRxcwahmE62JovbKe5r7AjANut",\ \ "9vLSZ1gujMzisVrK5r3ZBXLVJMrF3fp6BtAUDyD94nW2",\ \ "11111111111111111111111111111111",\ \ "5kR7n7QJv85NrwwXdYWZ52qkRcyvXqKWDPNooYcfDV6e",\ \ "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",\ \ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"\ \ \], "addressTableLookups": \[\], "header": { "numReadonlySignedAccounts": 0, "numReadonlyUnsignedAccounts": 4, "numRequiredSignatures": 1 }, "instructions": \[\ \ {\ \ "accounts": \[\ \ 0,\ \ 1,\ \ 0,\ \ 3,\ \ 2,\ \ 5\ \ \],\ \ "data": "1",\ \ "programIdIndex": 4,\ \ "stackHeight": 1\ \ }\ \ \], "recentBlockhash": "sammEBUaf2T7Tnr41i5YwWXXrMsTiP3NM6vbAc5tZGU" }, "signatures": \[\ \ "56rgv1Fqg7MHLoct3ESNx8DHeC2c5TFYyK1As35paWn2KYuRuXPFZK3XDEwkkZemVfmnKrkj17mMzz4N1d8kMYC4"\ \ \] }, "version": 0 }, "id": 1 } Is this page helpful? [Previous\ \ getTokenSupply](https://solana.com/docs/rpc/http/gettokensupply) [Next\ \ getTransactionCount](https://solana.com/docs/rpc/http/gettransactioncount) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # getBalance RPC Method | Solana [Solana Documentation](https://solana.com/docs) [Solana RPC Methods](https://solana.com/docs/rpc) [HTTP Methods](https://solana.com/docs/rpc/http) [getBalance RPC Method](https://solana.com/docs/rpc/http/getbalance) ===================================================================== Copy MarkdownOpen Returns the lamport balance of the account of provided Pubkey #### params stringrequired Pubkey of account to query, as base-58 encoded string. objectoptional Configuration object. commitmentstring minContextSlotnumber #### result u64 RpcResponse JSON object with value field set to the balance. cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getBalance", \> "params": \[\ \ \> "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",\ \ \> {\ \ \> "commitment": "finalized"\ \ \> }\ \ \> \] \> } \> ' Try it Response { "jsonrpc": "2.0", "result": { "context": { "slot": 1 }, "value": 0 }, "id": 1 } cURL Kit web3.js Rust $ curl https://api.devnet.solana.com -s -X \\ \> POST -H "Content-Type: application/json" -d ' \> { \> "jsonrpc": "2.0", \> "id": 1, \> "method": "getBalance", \> "params": \[\ \ \> "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",\ \ \> {\ \ \> "commitment": "finalized"\ \ \> }\ \ \> \] \> } \> ' Try it #### params stringrequired Pubkey of account to query, as base-58 encoded string. objectoptional Configuration object. commitmentstring minContextSlotnumber #### result Response { "jsonrpc": "2.0", "result": { "context": { "slot": 1 }, "value": 0 }, "id": 1 } u64 RpcResponse JSON object with value field set to the balance. Is this page helpful? [Previous\ \ getAccountInfo](https://solana.com/docs/rpc/http/getaccountinfo) [Next\ \ getBlock](https://solana.com/docs/rpc/http/getblock) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter getBalance RPC Method | Solana --- # Verify Address | Solana [Payments](https://solana.com/docs) [Send Payments](https://solana.com/docs/payments/send-payments) [Verify Address](https://solana.com/docs/payments/send-payments/verify-address) ================================================================================ Copy MarkdownOpen Sending tokens to the wrong address can result in permanent loss of funds. Address verification ensures you only send tokens to addresses that can properly receive and access them. See [How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) for core payment concepts. [Understanding Solana Addresses](https://solana.com/docs/payments/send-payments/verify-address#understanding-solana-addresses) ------------------------------------------------------------------------------------------------------------------------------- Solana accounts have two types of addresses, on-curve and off-curve. ### [On-Curve Addresses](https://solana.com/docs/payments/send-payments/verify-address#on-curve-addresses) Standard addresses are the public keys from Ed25519 keypairs. These addresses: * Have a corresponding private key that can sign transactions * Are used as wallet addresses ### [Off-Curve Addresses (PDAs)](https://solana.com/docs/payments/send-payments/verify-address#off-curve-addresses-pdas) [Program Derived Addresses](https://solana.com/docs/core/pda) are deterministically derived from a program ID and seeds. These addresses: * Do **not** have a corresponding private key * Can only be signed for by the program the address was derived from [Account Types in Payments](https://solana.com/docs/payments/send-payments/verify-address#account-types-in-payments) --------------------------------------------------------------------------------------------------------------------- Use the address to fetch an [account](https://solana.com/docs/core/accounts) from the network, check its program owner and account type to determine how to handle the address. Knowing whether an address is on-curve or off-curve does not tell you what type of account it is, what program owns it, or whether an account exists at that address. You must fetch the account from the network to determine these details. ### [System Program Accounts (Wallets)](https://solana.com/docs/payments/send-payments/verify-address#system-program-accounts-wallets) Accounts owned by the System Program are standard wallets. To send SPL tokens to a wallet, you derive and use its [Associated Token Account (ATA)](https://solana.com/docs/tokens/basics/create-token-account#whats-an-associated-token-account) . After deriving the ATA address, check whether the token account exists on-chain. If the ATA does not exist, you can include an instruction to create the recipient's token account in the same transaction as the transfer. However, this requires paying rent for the new token account. Since the recipient owns the ATA, the SOL paid for the rent cannot be recovered by the sender. Without safeguards, subsidizing ATA creation can be exploited. A malicious user could request a transfer, have their ATA created at your expense, close the ATA to reclaim the rent SOL, and repeat. ### [Token Accounts](https://solana.com/docs/payments/send-payments/verify-address#token-accounts) [Token accounts](https://solana.com/docs/tokens/basics/create-token-account) are owned by the Token Program or Token-2022 Program and hold token balances. If the address you receive is owned by a token program, you should verify the account is a token account (not a mint account) and matches the expected token mint account before sending. The Token Programs automatically validate that both token accounts in a transfer hold tokens of the same mint. If validation fails, the transaction is rejected and no funds are lost. ### [Mint Accounts](https://solana.com/docs/payments/send-payments/verify-address#mint-accounts) [Mint accounts](https://solana.com/docs/tokens/basics/create-mint) track the token supply and metadata of a specific token. Mint accounts are also owned by Token Programs but are **not** valid recipients for token transfers. Attempting to send tokens to a mint address results in a failed transaction, but no funds are lost. ### [Other Accounts](https://solana.com/docs/payments/send-payments/verify-address#other-accounts) Accounts owned by other programs require a policy decision. Some accounts (e.g. multisig wallets) may be valid token account owners, while others should be rejected. [Verification Flow](https://solana.com/docs/payments/send-payments/verify-address#verification-flow) ----------------------------------------------------------------------------------------------------- The following diagram shows a reference decision tree for validating an address: Address Verification Flow ### [Fetch account](https://solana.com/docs/payments/send-payments/verify-address#fetch-account) Use the address to fetch the account details from the network. ### [Account does not exist](https://solana.com/docs/payments/send-payments/verify-address#account-does-not-exist) If no account exists at this address, check whether the address is on-curve or off-curve: * **Off-curve (PDA)**: Conservatively reject the address to avoid sending to an ATA that may be inaccessible. Without an existing account, you cannot determine from the address alone which program derived this PDA or whether the address is for an ATA. Deriving an ATA for this address to send tokens could result in funds being locked in an inaccessible token account. * **On-curve**: This is a valid wallet address (public key) that hasn't been funded yet. Derive the ATA, check if it exists, and send tokens to it. You must make a policy decision whether to fund the creation of the ATA if it doesn't exist. ### [Account exists](https://solana.com/docs/payments/send-payments/verify-address#account-exists) If an account exists, check which program owns it: * **System Program**: This is a standard wallet. Derive the ATA, check if it exists, and send tokens to it. You must make a policy decision whether to fund the creation of the ATA if it doesn't exist. * **Token Program / Token-2022**: Verify the account is a token account (not a mint account) and that it holds the token (mint) you intend to send. If valid, send tokens directly to this address. If it's a mint account or a token account for a different mint, reject the address. * **Other Program**: This requires a policy decision. Some programs like multisig wallets may be acceptable owners of token accounts. If your policy allows it, derive the ATA and send. Otherwise, reject the address. [Demo](https://solana.com/docs/payments/send-payments/verify-address#demo) --------------------------------------------------------------------------- The following example shows only the address validation logic. This is reference code for illustration purposes. The demo does not show how to derive an ATA or build a transaction to send tokens. Refer to the [token account](https://solana.com/docs/tokens/basics/create-token-account#how-to-create-an-associated-token-account) and [token transfer](https://solana.com/docs/tokens/basics/transfer-tokens) documentation for example code. The demo below uses three possible outcomes: | Result | Meaning | Action | | --- | --- | --- | | `IS_WALLET` | Valid wallet address | Derive and send to associated token account | | `IS_TOKEN_ACCOUNT` | Valid token account | Send tokens directly to this address | | `REJECT` | Invalid address | Do not send | Demo /\*\* \* Validates an input address and classifies it as a wallet, token account, or invalid. \* \* @param inputAddress \- The address to validate \* @param rpc \- Optional RPC client (defaults to mainnet) \* @returns Classification result: \* - IS\_WALLET: Valid wallet address \* - IS\_TOKEN\_ACCOUNT: Valid token account \* - REJECT: Invalid address for transfers \*/ export async function validateAddress( inputAddress: Address, rpc: Rpc \= defaultRpc ): Promise { const account \= await fetchJsonParsedAccount(rpc, inputAddress); // Log the account data for demo console.log("\\nAccount:", account); // Account doesn't exist on-chain if (!account.exists) { // Off-curve = PDA that doesn't exist as an account // Reject conservatively to avoid sending to an address that may be inaccessible. if (isOffCurveAddress(inputAddress)) { return { type: "REJECT", reason: "PDA doesn't exist as an account" }; } // On-curve = valid keypair address, treat as unfunded wallet return { type: "IS\_WALLET" }; } // Account exists, check program owner const owner \= account.programAddress; // System Program = wallet if (owner \=== SYSTEM\_PROGRAM) { return { type: "IS\_WALLET" }; } // Token Program or Token-2022, check if token account if (owner \=== TOKEN\_PROGRAM || owner \=== TOKEN\_2022\_PROGRAM) { const accountType \= ( account.data as { parsedAccountMeta?: { type?: string } } ).parsedAccountMeta?.type; if (accountType \=== "account") { return { type: "IS\_TOKEN\_ACCOUNT" }; } // Reject if not a token account (mint account) return { type: "REJECT", reason: "Not a token account" }; } // Unknown program owner return { type: "REJECT", reason: "Unknown program owner" }; } // ============================================================================= // Examples // ============================================================================= Console RunClick to execute the code. Demo /\*\* \* Validates an input address and classifies it as a wallet, token account, or invalid. \* \* @param inputAddress \- The address to validate \* @param rpc \- Optional RPC client (defaults to mainnet) \* @returns Classification result: \* - IS\_WALLET: Valid wallet address \* - IS\_TOKEN\_ACCOUNT: Valid token account \* - REJECT: Invalid address for transfers \*/ export async function validateAddress( inputAddress: Address, rpc: Rpc \= defaultRpc ): Promise { const account \= await fetchJsonParsedAccount(rpc, inputAddress); // Log the account data for demo console.log("\\nAccount:", account); // Account doesn't exist on-chain if (!account.exists) { // Off-curve = PDA that doesn't exist as an account // Reject conservatively to avoid sending to an address that may be inaccessible. if (isOffCurveAddress(inputAddress)) { return { type: "REJECT", reason: "PDA doesn't exist as an account" }; } // On-curve = valid keypair address, treat as unfunded wallet return { type: "IS\_WALLET" }; } // Account exists, check program owner const owner \= account.programAddress; // System Program = wallet if (owner \=== SYSTEM\_PROGRAM) { return { type: "IS\_WALLET" }; } // Token Program or Token-2022, check if token account if (owner \=== TOKEN\_PROGRAM || owner \=== TOKEN\_2022\_PROGRAM) { const accountType \= ( account.data as { parsedAccountMeta?: { type?: string } } ).parsedAccountMeta?.type; if (accountType \=== "account") { return { type: "IS\_TOKEN\_ACCOUNT" }; } // Reject if not a token account (mint account) return { type: "REJECT", reason: "Not a token account" }; } // Unknown program owner return { type: "REJECT", reason: "Unknown program owner" }; } // ============================================================================= // Examples // ============================================================================= Console RunClick to execute the code. Is this page helpful? [Previous\ \ Fee Abstraction](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction) [Next\ \ Accept Payments](https://solana.com/docs/payments/accept-payments) ### Table of Contents [Understanding Solana Addresses](https://solana.com/docs/payments/send-payments/verify-address#understanding-solana-addresses) [On-Curve Addresses](https://solana.com/docs/payments/send-payments/verify-address#on-curve-addresses) [Off-Curve Addresses (PDAs)](https://solana.com/docs/payments/send-payments/verify-address#off-curve-addresses-pdas) [Account Types in Payments](https://solana.com/docs/payments/send-payments/verify-address#account-types-in-payments) [System Program Accounts (Wallets)](https://solana.com/docs/payments/send-payments/verify-address#system-program-accounts-wallets) [Token Accounts](https://solana.com/docs/payments/send-payments/verify-address#token-accounts) [Mint Accounts](https://solana.com/docs/payments/send-payments/verify-address#mint-accounts) [Other Accounts](https://solana.com/docs/payments/send-payments/verify-address#other-accounts) [Verification Flow](https://solana.com/docs/payments/send-payments/verify-address#verification-flow) [Fetch account](https://solana.com/docs/payments/send-payments/verify-address#fetch-account) [Account does not exist](https://solana.com/docs/payments/send-payments/verify-address#account-does-not-exist) [Account exists](https://solana.com/docs/payments/send-payments/verify-address#account-exists) [Demo](https://solana.com/docs/payments/send-payments/verify-address#demo) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/send-payments/verify-address.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Agentic Payments | Solana [Payments](https://solana.com/docs) [Agentic Payments](https://solana.com/docs/payments/agentic-payments) ====================================================================== Copy MarkdownOpen AI agents are increasingly autonomous in their workflows: writing code, fetching data, provisioning resources, and more. To operate fully independently, they need a way to make "micropayments" for services programmatically, in real-time, at minimal cost. Traditional payment rails don't work for micropayments. Solana's sub-cent fees and sub-second finality make this technically and economically viable. [Why is this important?](https://solana.com/docs/payments/agentic-payments#why-is-this-important) -------------------------------------------------------------------------------------------------- For example, imagine a developer using an LLM to build an application needs data from a paid API. To fetch some important data, a developer would need to stop their workflow, research APIs, select a provider, create an account, add a payment method, generate an API key, copy the key into their environment, and then resume their workflow. This friction breaks flow state. For AI-assisted workflows, it's a blocker. Instead, with agentic payments, the agent can make the request, pay for it, and continue with their workflow. No accounts. No API keys. No manual intervention. [The x402 Protocol](https://solana.com/docs/payments/agentic-payments#the-x402-protocol) ----------------------------------------------------------------------------------------- Agentic payments need a way for clients and servers to negotiate payment terms over standard web infrastructure without disrupting traditional web interfaces. The micropayment space is still nascent and new tools and standards will likely emerge as the space evolves. The [x402 protocol](https://www.x402.org/) , however, has emerged as an early standard with strong ecosystem support. x402 uses [HTTP's 402 "Payment Required"](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/402) status code—a standard since HTTP/1.1 that only became practical with blockchain settlement. ### [How it works](https://solana.com/docs/payments/agentic-payments#how-it-works) The client makes a request, receives a 402 with payment terms, then retries with a signed payment. The server delegates verification and settlement to a facilitator, an optional intermediary that handles the on-chain transaction submission. Once the facilitator confirms settlement, the server returns the requested content. This separation lets API providers accept payments without managing any on-chain infrastructure directly. x402 Flow Diagram The protocol is stateless (no sessions or API keys), works with standard HTTP infrastructure, and supports any SPL token the server accepts. Here's a snippet of how to set up an Express server using x402 middleware: app.use( paymentMiddleware( { "GET /costly-data": { accepts: \[\ \ {\ \ scheme: "exact",\ \ price: "$0.001",\ \ network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",\ \ payTo: svmAddress\ \ }\ \ \], description: "Costly data", mimeType: "application/json" } }, new x402ResourceServer(facilitatorClient).register( "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme() ) ) ); app.get("/costly-data", (req, res) \=> { res.send({ report: { data: "costly data" } }); }); To learn more on x402, check out our guides: [### Introduction to x402\ \ Protocol fundamentals and SDK options for building payment-enabled APIs.](https://solana.com/developers/guides/getstarted/intro-to-x402) [### Build with Kora\ \ Implement gasless x402 payments using Kora's signing infrastructure.](https://solana.com/developers/guides/getstarted/build-a-x402-facilitator) ### [x402 Tooling](https://solana.com/docs/payments/agentic-payments#x402-tooling) | SDK | Description | | --- | --- | | [Corbits](https://corbits.dev/) | Solana-first x402 implementation | | [MCPay.tech](https://mcpay.tech/) | Pay-per-request for MCP servers | | [PayAI](https://payai.network/) | x402 facilitator with Solana support | | [x402 GitHub](https://github.com/coinbase/x402) | Reference implementation | | [ACK](https://github.com/agentcommercekit/ack) | Agent Commerce Kit | | [A2A x402](https://github.com/google-agentic-commerce/a2a-x402) | Google's agent-to-agent payments | Is this page helpful? [Previous\ \ Deferred Execution](https://solana.com/docs/payments/advanced-payments/deferred-execution) [Next\ \ Developer Tools](https://solana.com/docs/payments/developer-tools) ### Table of Contents [Why is this important?](https://solana.com/docs/payments/agentic-payments#why-is-this-important) [The x402 Protocol](https://solana.com/docs/payments/agentic-payments#the-x402-protocol) [How it works](https://solana.com/docs/payments/agentic-payments#how-it-works) [x402 Tooling](https://solana.com/docs/payments/agentic-payments#x402-tooling) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/agentic-payments.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Accept Payments | Solana [Payments](https://solana.com/docs) [Accept Payments](https://solana.com/docs/payments/accept-payments) ==================================================================== Copy MarkdownOpen Accept payments on Solana using drop-in components, the Solana Pay protocol, or direct RPC integration. [Receiving Address Convention](https://solana.com/docs/payments/accept-payments#receiving-address-convention) -------------------------------------------------------------------------------------------------------------- On Solana, **share your wallet address, not your token account**. It is typical for the sender to derive the appropriate [Associated Token Account (ATA)](https://solana.com/docs/payments/how-payments-work#token-accounts) for whatever token they're sending (see [Sending Payments](https://solana.com/docs/payments/send-payments) for more details). **Example:** Share `7EcDhS...` (your wallet), not `9xKpQ...` (your USDC token account). For point-of-sale and e-commerce, see [Solana Pay](https://solana.com/docs/payments/accept-payments/solana-pay) for QR codes and payment URLs, or [Payment Button](https://solana.com/docs/payments/accept-payments/payment-button) for drop-in React components. [Integration Options](https://solana.com/docs/payments/accept-payments#integration-options) -------------------------------------------------------------------------------------------- | Approach | Best For | Complexity | | --- | --- | --- | | [Payment Button](https://solana.com/docs/payments/accept-payments/payment-button) | React apps, quick integration | Low | | [Solana Pay](https://solana.com/docs/payments/accept-payments/solana-pay) | QR codes, payment links, POS | Medium | | [Direct RPC](https://solana.com/docs/payments/interacting-with-solana) | Custom flows, full control | Higher | [Verification](https://solana.com/docs/payments/accept-payments#verification) ------------------------------------------------------------------------------ After receiving a payment, verify it landed using [Verification Tools](https://solana.com/docs/payments/accept-payments/verification-tools) . For high-volume applications, see [Indexing](https://solana.com/docs/payments/accept-payments/indexing) for production-grade transaction monitoring. [### Payment Button\ \ Drop-in React component for Solana payments](https://solana.com/docs/payments/accept-payments/payment-button) [### Verification Tools\ \ Verify incoming stablecoin payments and reconcile them with your orders.](https://solana.com/docs/payments/accept-payments/verification-tools) [### Indexing\ \ Production-grade transaction monitoring for high-volume payment systems](https://solana.com/docs/payments/accept-payments/indexing) Is this page helpful? [Previous\ \ Verify Address](https://solana.com/docs/payments/send-payments/verify-address) [Next\ \ Payment Button](https://solana.com/docs/payments/accept-payments/payment-button) ### Table of Contents [Receiving Address Convention](https://solana.com/docs/payments/accept-payments#receiving-address-convention) [Integration Options](https://solana.com/docs/payments/accept-payments#integration-options) [Verification](https://solana.com/docs/payments/accept-payments#verification) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/accept-payments/index.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Program Derived Address | Solana [Solana Documentation](https://solana.com/docs) Getting Started[Quick Start](https://solana.com/docs/intro/quick-start) [Program Derived Address](https://solana.com/docs/intro/quick-start/program-derived-address) ============================================================================================= Copy MarkdownOpen In this section, you'll learn how to build a basic Create, Read, Update, Delete (CRUD) program. This guide demonstrates a simple program where users can create, update, and delete a message. Each message exists in an account with a deterministic address derived from the program itself (Program Derived Address or PDA). This guide walks you through building and testing a Solana program using the Anchor framework while demonstrating Program Derived Addresses (PDAs). For more details, refer to the [Program Derived Addresses](https://solana.com/docs/core/pda) page. For reference, you can view the [final code](https://beta.solpg.io/668304cfcffcf4b13384d20a) after completing both the PDA and Cross-Program Invocation (CPI) sections. ### [Starter Code](https://solana.com/docs/intro/quick-start/program-derived-address#starter-code) Start by opening this [Solana Playground link](https://beta.solpg.io/66734b7bcffcf4b13384d1ad) with the starter code. Then click the "Import" button to add the program to your Solana Playground projects. Import In the `lib.rs` file, you'll find a program with the `create`, `update`, and `delete` instructions to add in the following steps. lib.rs use anchor\_lang::prelude::\*; declare\_id!("8KPzbM2Cwn4Yjak7QYAEH9wyoQh86NcBicaLuzPaejdw"); #\[program\] pub mod pda { use super::\*; pub fn create(\_ctx: Context) \-> Result<()> { Ok(()) } pub fn update(\_ctx: Context) \-> Result<()> { Ok(()) } pub fn delete(\_ctx: Context) \-> Result<()> { Ok(()) } } #\[derive(Accounts)\] pub struct Create {} #\[derive(Accounts)\] pub struct Update {} #\[derive(Accounts)\] pub struct Delete {} #\[account\] pub struct MessageAccount {} Before beginning, run `build` in the Playground terminal to check the starter program builds successfully. Terminal $ build Copy \[show output\] ### [Define Message Account Type](https://solana.com/docs/intro/quick-start/program-derived-address#define-message-account-type) First, define the structure for the message account that the program creates. This structure defines the data to store in the account created by the program. In `lib.rs`, update the `MessageAccount` struct with the following: lib.rs #\[account\] pub struct MessageAccount { pub user: Pubkey, pub message: String, pub bump: u8, } ### Diff ### Explanation Build the program again by running `build` in the terminal. Terminal $ build Copy This code defines what data to store on the message account. Next, you'll add the program instructions. ### [Add Create Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#add-create-instruction) Now, add the `create` instruction that creates and initializes the `MessageAccount`. Start by defining the accounts required for the instruction by updating the `Create` struct with the following: lib.rs #\[derive(Accounts)\] #\[instruction(message: String)\] pub struct Create<'info\> { #\[account(mut)\] pub user: Signer<'info\>, #\[account(\ \ init,\ \ seeds \= \[b"message", user.key().as\_ref()\],\ \ bump,\ \ payer \= user,\ \ space \= 8 + 32 + 4 + message.len() + 1\ \ )\] pub message\_account: Account<'info, MessageAccount\>, pub system\_program: Program<'info, System\>, } ### Diff ### Explanation Next, add the business logic for the `create` instruction by updating the `create` function with the following: lib.rs pub fn create(ctx: Context, message: String) \-> Result<()> { msg!("Create Message: {}", message); let account\_data \= &mut ctx.accounts.message\_account; account\_data.user \= ctx.accounts.user.key(); account\_data.message \= message; account\_data.bump \= ctx.bumps.message\_account; Ok(()) } ### Diff ### Explanation Rebuild the program. Terminal $ build Copy ### [Add Update Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#add-update-instruction) Next, add the `update` instruction to change the `MessageAccount` with a new message. Like the previous step, first specify the accounts required by the `update` instruction. Update the `Update` struct with the following: lib.rs #\[derive(Accounts)\] #\[instruction(message: String)\] pub struct Update<'info\> { #\[account(mut)\] pub user: Signer<'info\>, #\[account(\ \ mut,\ \ seeds \= \[b"message", user.key().as\_ref()\],\ \ bump \= message\_account.bump,\ \ realloc \= 8 + 32 + 4 + message.len() + 1,\ \ realloc::payer \= user,\ \ realloc::zero \= true,\ \ )\] pub message\_account: Account<'info, MessageAccount\>, pub system\_program: Program<'info, System\>, } ### Diff ### Explanation Next, add the logic for the `update` instruction. lib.rs pub fn update(ctx: Context, message: String) \-> Result<()> { msg!("Update Message: {}", message); let account\_data \= &mut ctx.accounts.message\_account; account\_data.message \= message; Ok(()) } ### Diff ### Explanation Rebuild the program Terminal $ build Copy ### [Add Delete Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#add-delete-instruction) Next, add the `delete` instruction to close the `MessageAccount`. Update the `Delete` struct with the following: lib.rs #\[derive(Accounts)\] pub struct Delete<'info\> { #\[account(mut)\] pub user: Signer<'info\>, #\[account(\ \ mut,\ \ seeds \= \[b"message", user.key().as\_ref()\],\ \ bump \= message\_account.bump,\ \ close \= user,\ \ )\] pub message\_account: Account<'info, MessageAccount\>, } ### Diff ### Explanation Next, add the logic for the `delete` instruction. lib.rs pub fn delete(\_ctx: Context) \-> Result<()> { msg!("Delete Message"); Ok(()) } ### Diff ### Explanation Rebuild the program. Terminal $ build Copy ### [Deploy Program](https://solana.com/docs/intro/quick-start/program-derived-address#deploy-program) You've now completed the basic CRUD program. Deploy the program by running `deploy` in the Playground terminal. In this example, you'll deploy the program to the devnet, a Solana cluster for development testing. The Playground wallet connects to the devnet by default. Ensure your Playground wallet has devnet SOL to pay for the program deployment. Get devnet SOL from the [Solana Faucet](https://faucet.solana.com/) . Terminal $ deploy Copy \[show output\] ### [Set Up Test File](https://solana.com/docs/intro/quick-start/program-derived-address#set-up-test-file) The starter code also includes a test file in `anchor.test.ts`. anchor.test.ts import { PublicKey } from "@solana/web3.js"; describe("pda", () \=> { it("Create Message Account", async () \=> {}); it("Update Message Account", async () \=> {}); it("Delete Message Account", async () \=> {}); }); Add the code below inside `describe()`, but before the `it()` sections. anchor.test.ts const program \= pg.program; const wallet \= pg.wallet; const \[messagePda, messageBump\] \= PublicKey.findProgramAddressSync( \[Buffer.from("message"), wallet.publicKey.toBuffer()\], program.programId ); ### Diff ### Explanation Run the test file by running `test` in the Playground terminal to check that it runs as expected. The next steps add the actual tests. Terminal $ test Copy \[show output\] ### [Invoke Create Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#invoke-create-instruction) Update the first test with the following: anchor.test.ts it("Create Message Account", async () \=> { const message \= "Hello, World!"; const transactionSignature \= await program.methods .create(message) .accounts({ messageAccount: messagePda }) .rpc({ commitment: "confirmed" }); const messageAccount \= await program.account.messageAccount.fetch( messagePda, "confirmed" ); console.log(JSON.stringify(messageAccount, null, 2)); console.log( "Transaction Signature:", \`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana\` ); }); ### Diff ### Explanation ### [Invoke Update Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#invoke-update-instruction) Update the second test with the following: anchor.test.ts it("Update Message Account", async () \=> { const message \= "Hello, Solana!"; const transactionSignature \= await program.methods .update(message) .accounts({ messageAccount: messagePda }) .rpc({ commitment: "confirmed" }); const messageAccount \= await program.account.messageAccount.fetch( messagePda, "confirmed" ); console.log(JSON.stringify(messageAccount, null, 2)); console.log( "Transaction Signature:", \`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana\` ); }); ### Diff ### Explanation ### [Invoke Delete Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#invoke-delete-instruction) Update the third test with the following: anchor.test.ts it("Delete Message Account", async () \=> { const transactionSignature \= await program.methods .delete() .accounts({ messageAccount: messagePda }) .rpc({ commitment: "confirmed" }); const messageAccount \= await program.account.messageAccount.fetchNullable( messagePda, "confirmed" ); console.log("Expect Null:", JSON.stringify(messageAccount, null, 2)); console.log( "Transaction Signature:", \`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana\` ); }); ### Diff ### Explanation ### [Run Test](https://solana.com/docs/intro/quick-start/program-derived-address#run-test) After preparing your tests, run the test file with `test` in the Playground terminal. This command runs the tests against the program deployed on the devnet and logs links to SolanaFM to view the transaction details. Terminal $ test Copy \[show output\] Inspect the SolanaFM links to view the transaction details. Note that in this example, if you run the test again, the `create` instruction fails because `messageAccount` already exists as an account. Only one account can exist for a given PDA. Is this page helpful? [Previous\ \ Deploy a Program](https://solana.com/docs/intro/quick-start/deploying-programs) [Next\ \ Composing Multiple Programs](https://solana.com/docs/intro/quick-start/cross-program-invocation) ### Table of Contents [Starter Code](https://solana.com/docs/intro/quick-start/program-derived-address#starter-code) [Define Message Account Type](https://solana.com/docs/intro/quick-start/program-derived-address#define-message-account-type) [Add Create Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#add-create-instruction) [Add Update Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#add-update-instruction) [Add Delete Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#add-delete-instruction) [Deploy Program](https://solana.com/docs/intro/quick-start/program-derived-address#deploy-program) [Set Up Test File](https://solana.com/docs/intro/quick-start/program-derived-address#set-up-test-file) [Invoke Create Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#invoke-create-instruction) [Invoke Update Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#invoke-update-instruction) [Invoke Delete Instruction](https://solana.com/docs/intro/quick-start/program-derived-address#invoke-delete-instruction) [Run Test](https://solana.com/docs/intro/quick-start/program-derived-address#run-test) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/intro/quick-start/program-derived-address.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Stake Accounts | Solana [Solana Documentation](https://solana.com/docs) References[Staking](https://solana.com/docs/references/staking) [Stake Accounts](https://solana.com/docs/references/staking/stake-accounts) ============================================================================ Copy MarkdownOpen A stake account on Solana can be used to delegate tokens to validators on the network to potentially earn rewards for the owner of the stake account. Stake accounts are created and managed differently than a traditional wallet address, known as a _system account_. A system account is only able to send and receive SOL from other accounts on the network, whereas a stake account supports more complex operations needed to manage a delegation of tokens. Stake accounts on Solana also work differently than those of other Proof-of-Stake blockchain networks that you may be familiar with. This document describes the high-level structure and functions of a Solana stake account. ### [Account Address](https://solana.com/docs/references/staking/stake-accounts#account-address) Each stake account has a unique address which can be used to look up the account information in the command line or in any network explorer tools. However, unlike a wallet address in which the holder of the address's keypair controls the wallet, the keypair associated with a stake account address does not necessarily have any control over the account. In fact, a keypair or private key may not even exist for a stake account's address. The only time a stake account's address has a keypair file is when [creating a stake account using the command line tools](https://docs.anza.xyz/cli/examples/delegate-stake#create-a-stake-account) . A new keypair file is created first only to ensure that the stake account's address is new and unique. ### [Understanding Account Authorities](https://solana.com/docs/references/staking/stake-accounts#understanding-account-authorities) Certain types of accounts may have one or more _signing authorities_ associated with a given account. An account authority is used to sign certain transactions for the account it controls. This is different from some other blockchain networks where the holder of the keypair associated with the account's address controls all of the account's activity. Each stake account has two signing authorities specified by their respective address, each of which is authorized to perform certain operations on the stake account. The _stake authority_ is used to sign transactions for the following operations: * Delegating stake * Deactivating the stake delegation * Splitting the stake account, creating a new stake account with a portion of the funds in the first account * Merging two stake accounts into one * Setting a new stake authority The _withdraw authority_ signs transactions for the following: * Withdrawing un-delegated stake into a wallet address * Setting a new withdraw authority * Setting a new stake authority The stake authority and withdraw authority are set when the stake account is created, and they can be changed to authorize a new signing address at any time. The stake and withdraw authority can be the same address or two different addresses. The withdraw authority keypair holds more control over the account as it is needed to liquidate the tokens in the stake account, and can be used to reset the stake authority if the stake authority keypair becomes lost or compromised. Securing the withdraw authority against loss or theft is of utmost importance when managing a stake account. ### [Multiple Delegations](https://solana.com/docs/references/staking/stake-accounts#multiple-delegations) Each stake account may only be used to delegate to one validator at a time. All of the tokens in the account are either delegated or un-delegated, or in the process of becoming delegated or un-delegated. To delegate a fraction of your tokens to a validator, or to delegate to multiple validators, you must create multiple stake accounts. This can be accomplished by creating multiple stake accounts from a wallet address containing some tokens, or by creating a single large stake account and using the stake authority to split the account into multiple accounts with token balances of your choosing. The same stake and withdraw authorities can be assigned to multiple stake accounts. ### [Merging stake accounts](https://solana.com/docs/references/staking/stake-accounts#merging-stake-accounts) Two stake accounts that have the same authorities and lockup can be merged into a single resulting stake account. A merge is possible between two stakes in the following states with no additional conditions: * two deactivated stakes * an inactive stake into an activating stake during its activation epoch For the following cases, the voter pubkey and vote credits observed must match: * two activated stakes * two activating accounts that share an activation epoch, during the activation epoch All other combinations of stake states will fail to merge, including all "transient" states, where a stake is activating or deactivating with a non-zero effective stake. ### [Delegation Warmup and Cooldown](https://solana.com/docs/references/staking/stake-accounts#delegation-warmup-and-cooldown) When a stake account is delegated, or a delegation is deactivated, the operation does not take effect immediately. A delegation or deactivation takes several [epochs](https://solana.com/docs/references/terminology#epoch) to complete, with a fraction of the delegation becoming active or inactive at each epoch boundary after the transaction containing the instructions has been submitted to the cluster. There is also a limit on how much total stake can become delegated or deactivated in a single epoch, to prevent large sudden changes in stake across the network as a whole. Since warmup and cooldown are dependent on the behavior of other network participants, their exact duration is difficult to predict. Details on the warmup and cooldown timing can be found [here](https://docs.anza.xyz/consensus/stake-delegation-and-rewards#stake-warmup-cooldown-withdrawal) . ### [Lockups](https://solana.com/docs/references/staking/stake-accounts#lockups) Stake accounts can have a lockup which prevents the tokens they hold from being withdrawn before a particular date or epoch has been reached. While locked up, the stake account can still be delegated, un-delegated, or split, and its stake authority can be changed as normal. Only withdrawal into another wallet or updating the withdraw authority is not allowed. A lockup can only be added when a stake account is first created, but it can be modified later, by the _lockup authority_ or _custodian_, the address of which is also set when the account is created. ### [Destroying a Stake Account](https://solana.com/docs/references/staking/stake-accounts#destroying-a-stake-account) Like other types of accounts on the Solana network, a stake account that has a balance of 0 SOL is no longer tracked. If a stake account is not delegated and all of the tokens it contains are withdrawn to a wallet address, the account at that address is effectively destroyed, and will need to be manually re-created for the address to be used again. ### [Viewing Stake Accounts](https://solana.com/docs/references/staking/stake-accounts#viewing-stake-accounts) Stake account details can be viewed on the [Solana Explorer](http://explorer.solana.com/) by copying and pasting an account address into the search bar. Is this page helpful? [Previous\ \ Staking](https://solana.com/docs/references/staking) [Next\ \ Stake Programming](https://solana.com/docs/references/staking/stake-program) ### Table of Contents [Account Address](https://solana.com/docs/references/staking/stake-accounts#account-address) [Understanding Account Authorities](https://solana.com/docs/references/staking/stake-accounts#understanding-account-authorities) [Multiple Delegations](https://solana.com/docs/references/staking/stake-accounts#multiple-delegations) [Merging stake accounts](https://solana.com/docs/references/staking/stake-accounts#merging-stake-accounts) [Delegation Warmup and Cooldown](https://solana.com/docs/references/staking/stake-accounts#delegation-warmup-and-cooldown) [Lockups](https://solana.com/docs/references/staking/stake-accounts#lockups) [Destroying a Stake Account](https://solana.com/docs/references/staking/stake-accounts#destroying-a-stake-account) [Viewing Stake Accounts](https://solana.com/docs/references/staking/stake-accounts#viewing-stake-accounts) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/references/staking/stake-accounts.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Stake Programming | Solana [Solana Documentation](https://solana.com/docs) References[Staking](https://solana.com/docs/references/staking) [Stake Programming](https://solana.com/docs/references/staking/stake-program) ============================================================================== Copy MarkdownOpen To maximize stake distribution, decentralization, and censorship resistance on the Solana network, staking can be performed programmatically. The team and community have developed several on-chain and offchain programs to make stakes easier to manage. ### [Solana Foundation Delegation Program](https://solana.com/docs/references/staking/stake-program#solana-foundation-delegation-program) The [Solana Foundation Delegation Program](https://solana.org/delegation-program) is designed to serve the needs of the network by targeting the following goals: 1. Maximize decentralization, reliability, and performance of Solana 2. Maximize the number of validators who have diverse sources of stake 3. Sustain a large and representative testnet ### [Stake Pools](https://solana.com/docs/references/staking/stake-program#stake-pools) This on-chain program pools together SOL to be staked by a manager, allowing SOL holders to stake and earn rewards without managing stakes. Users deposit SOL in exchange for SPL tokens (staking derivatives) that represent their ownership in the stake pool. The pool manager stakes deposited SOL according to their strategy, perhaps using a variant of an auto-delegation bot as described above. As stakes earn rewards, the pool and pool tokens grow proportionally in value. Finally, pool token holders can send SPL tokens back to the stake pool to redeem SOL, thereby participating in decentralization with much less work required. More information can be found at the [SPL stake pool documentation](https://spl.solana.com/stake-pool) . Is this page helpful? [Previous\ \ Stake Accounts](https://solana.com/docs/references/staking/stake-accounts) [Next\ \ Terminology](https://solana.com/docs/references/terminology) ### Table of Contents [Solana Foundation Delegation Program](https://solana.com/docs/references/staking/stake-program#solana-foundation-delegation-program) [Stake Pools](https://solana.com/docs/references/staking/stake-program#stake-pools) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/references/staking/stake-program.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Go SDK for Solana | Solana [Solana Documentation](https://solana.com/docs) Solana SDKsCommunity SDKs [Go SDK for Solana](https://solana.com/docs/clients/community/go) ================================================================== Copy MarkdownOpen There's a [Go SDK](https://github.com/gagliardetto/solana-go) that supports most functions to interact with Solana. If you're using Anchor for your Solana programs, you will be able to use [anchor-go](https://github.com/gagliardetto/anchor-go) with your idl to produce a Golang compatible client. [Installation](https://solana.com/docs/clients/community/go#installation) -------------------------------------------------------------------------- Terminal go get github.com/gagliardetto/solana-go@v1.12.0 [More Documentation](https://solana.com/docs/clients/community/go#more-documentation) -------------------------------------------------------------------------------------- Please visit the [Go SDK documentation](https://github.com/gagliardetto/solana-go?tab=readme-ov-file#installation) for more information on using this Go SDK with Solana. Is this page helpful? [Previous\ \ Java SDK](https://solana.com/docs/clients/community/java) [Next\ \ Solana Gaming SDKs](https://solana.com/docs/clients/community/game-sdks) ### Table of Contents [Installation](https://solana.com/docs/clients/community/go#installation) [More Documentation](https://solana.com/docs/clients/community/go#more-documentation) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/clients/community/go.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Python SDK for Solana | Solana [Solana Documentation](https://solana.com/docs) Solana SDKsCommunity SDKs [Python SDK for Solana](https://solana.com/docs/clients/community/python) ========================================================================== Copy MarkdownOpen [Solana Python SDK](https://solana.com/docs/clients/community/python#solana-python-sdk) ---------------------------------------------------------------------------------------- There are two packages that are useful for developing with Python: [`@kevinheavy/solana.py`](https://github.com/michaelhly/solana-py) * Solana.py is the base Python library for interacting with Solana. * You can use it to build transactions and interact with the [Solana JSON RPC API](https://solana.com/docs/rpc) , much like you would do with [solana-web3.js](https://github.com/solana-labs/solana-web3.js/) * It also covers the [SPL Token Program](https://spl.solana.com/token) . * [Latest Documentation](https://michaelhly.github.io/solana-py/) . [`@kevinheavey/solders`](https://github.com/kevinheavey/solders) * `solders` is a high-performance Python toolkit for Solana, written in Rust. It provides robust solutions in the following areas: * Core SDK functionality: keypairs, pubkeys, signing and serializing transactions. * RPC: building requests and parsing responses (for networking and asynchronous APIs, [solana-py](https://michaelhly.github.io/solana-py/rpc/async_api/) is the recommended option). * Integration testing: the `solders.litesvm` module is an alternative to `solana-test-validator` that's much more convenient and **much** faster. It's based on [solana-program-test](https://crates.io/crates/solana-program-test) . [Solana Client Python SDK](https://solana.com/docs/clients/community/python#solana-client-python-sdk) ------------------------------------------------------------------------------------------------------ If you want to interact with Solana contracts with Python, you can use clients SDK to render Solana rust contracts to Python clients, if only you can get the IDL file of the contract. [`Codama-py`](https://www.npmjs.com/package/codama-py) * Standardize any Solana on-chain contract program to [`Codama IDL`](https://github.com/codama-idl/codama) and generate an interactive Python client. * Supports both Anchor and custom programs. [`Anchor-py`](https://github.com/kevinheavey/anchorpy) * Anchor-py is a Python client for Anchor programs. It can generate clients from Anchor IDL files, and interact with Anchor programs. [Solana Python Cookbook](https://solana.com/docs/clients/community/python#solana-python-cookbook) -------------------------------------------------------------------------------------------------- [`Solana Python Cookbook`](https://solana.com/developers/cookbook) A collection of examples and recipes for developing Solana using Python SDK. Is this page helpful? [Previous\ \ Typescript SDK](https://solana.com/docs/clients/official/javascript) [Next\ \ Java SDK](https://solana.com/docs/clients/community/java) ### Table of Contents [Solana Python SDK](https://solana.com/docs/clients/community/python#solana-python-sdk) [Solana Client Python SDK](https://solana.com/docs/clients/community/python#solana-client-python-sdk) [Solana Python Cookbook](https://solana.com/docs/clients/community/python#solana-python-cookbook) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/clients/community/python.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Java SDK for Solana | Solana [Solana Documentation](https://solana.com/docs) Solana SDKsCommunity SDKs [Java SDK for Solana](https://solana.com/docs/clients/community/java) ====================================================================== Copy MarkdownOpen There's a [Java SDK](https://sava.software/welcome) built by [Sava Engineering](https://sava.engineering/) that supports most functions to interact with Solana. If you're using Anchor for your Solana programs, you will be able to use [anchor-src-gen](https://sava.software/utilities/anchor-src-gen) with your idl to produce a Java compatible client. [Installation](https://solana.com/docs/clients/community/java#installation) ---------------------------------------------------------------------------- ### [Maven](https://solana.com/docs/clients/community/java#maven) pom.xml software.sava sava-core VERSION software.sava sava-rpc VERSION gpr-sava sava https://maven.pkg.github.com/sava-software/sava gpr-json-iterator json-iterator https://maven.pkg.github.com/comodal/json-iterator settings.xml gpr-sava GITHUB\_USERNAME GITHUB\_PERSONAL\_ACCESS\_TOKEN gpr-json-iterator GITHUB\_USERNAME GITHUB\_PERSONAL\_ACCESS\_TOKEN ### [Gradle](https://solana.com/docs/clients/community/java#gradle) build.gradle repositories { maven { url \= "https://maven.pkg.github.com/sava-software/sava" credentials { username \= GITHUB\_USERNAME password \= GITHUB\_PERSONAL\_ACCESS\_TOKEN } } maven { url \= "https://maven.pkg.github.com/comodal/json-iterator" credentials { username \= GITHUB\_USERNAME password \= GITHUB\_PERSONAL\_ACCESS\_TOKEN } } } dependencies { implementation "software.sava:sava-core:$VERSION" implementation "software.sava:sava-rpc:$VERSION" } [More Documentation](https://solana.com/docs/clients/community/java#more-documentation) ---------------------------------------------------------------------------------------- Please visit the [Sava Software documentation](https://sava.software/welcome) for more information on using this Java SDK with Solana. Is this page helpful? [Previous\ \ Python SDK](https://solana.com/docs/clients/community/python) [Next\ \ Go SDK](https://solana.com/docs/clients/community/go) ### Table of Contents [Installation](https://solana.com/docs/clients/community/java#installation) [Maven](https://solana.com/docs/clients/community/java#maven) [Gradle](https://solana.com/docs/clients/community/java#gradle) [More Documentation](https://solana.com/docs/clients/community/java#more-documentation) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/clients/community/java.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Fee Abstraction | Solana [Payments](https://solana.com/docs) [Send Payments](https://solana.com/docs/payments/send-payments) [Payment Processing](https://solana.com/docs/payments/send-payments/payment-processing) [Fee Abstraction](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction) ===================================================================================================== Copy MarkdownOpen Every Solana transaction requires SOL to pay network fees. But users coming to your payment application expect to transact in stablecoins—not manage a second token balance. Fee abstraction removes this friction by having someone else pay the fees. This guide covers two levels: 1. **How fee sponsorship works** — the underlying Solana primitive 2. **Fee abstraction at scale with Kora** — a production-ready fee abstraction service [How Fee Sponsorship Works](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#how-fee-sponsorship-works) ----------------------------------------------------------------------------------------------------------------------------------------- Solana transactions have a designated fee payer—the account that pays the network fee. By default, this is the first signer. But you can specify a different account as the fee payer, allowing a third party (the "sponsor") to cover fees on behalf of the sender. Both the sender and sponsor must sign the transaction: * The **sender** signs to authorize the transfer of their tokens * The **sponsor** signs to authorize payment of the network fee See [How Payments Work on Solana](https://solana.com/docs/payments/how-payments-work) for core payment concepts. The steps below show the core flow. See the [Demo](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#demo) for complete runnable code. Create a Sponsor Account ------------------------ Generate a separate keypair for the sponsor who will pay transaction fees. The sponsor needs SOL for fees but doesn't need to hold the tokens being transferred. Sponsor Transaction Fee const sponsor \= (await generateKeypair()).signer; Create Transfer Instruction --------------------------- Create the token transfer instruction with the sender as authority. The sender owns the tokens and must sign the transfer. Sponsor Transaction Fee const sponsor \= (await generateKeypair()).signer; const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender, // Sender signs for the transfer amount: 250\_000n // adjusted for the mint's decimals }); Send with Sponsor as Fee Payer ------------------------------ Use `prepareAndSend` with both `authority` (the sender who signs the transfer) and `feePayer` (the sponsor who pays fees). Both must sign the transaction. Sponsor Transaction Fee const sponsor \= (await generateKeypair()).signer; const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender, amount: 250\_000n }); const signature \= await client.transaction.prepareAndSend({ authority: sender, // Signs the transfer instruction feePayer: sponsor, // Pays the transaction fees instructions: \[transferInstruction\], version: 0 }); Create a Sponsor Account ------------------------ Generate a separate keypair for the sponsor who will pay transaction fees. The sponsor needs SOL for fees but doesn't need to hold the tokens being transferred. Create Transfer Instruction --------------------------- Create the token transfer instruction with the sender as authority. The sender owns the tokens and must sign the transfer. Send with Sponsor as Fee Payer ------------------------------ Use `prepareAndSend` with both `authority` (the sender who signs the transfer) and `feePayer` (the sponsor who pays fees). Both must sign the transaction. Sponsor Transaction Fee const sponsor \= (await generateKeypair()).signer; ### [Demo](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#demo) Demo // Click ">" icon on left to expand demo imports // Generate keypairs for sender, recipient, and sponsor (fee payer) const sender \= (await generateKeypair()).signer; const recipient \= (await generateKeypair()).signer; const sponsor \= (await generateKeypair()).signer; console.log("Sender Address:", sender.address); console.log("Recipient Address:", recipient.address); console.log("Sponsor Address (Fee Payer):", sponsor.address); // Demo Setup: Create client, mint account, token accounts, and fund with initial tokens const { client, mint } \= await demoSetup(sender, recipient, sponsor); console.log("\\nMint Address:", mint.address); // Derive the Associated Token Accounts addresses (ATAs) for sender and recipient const \[senderAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: sender.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); const \[recipientAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: recipient.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); console.log("Sender Token Account:", senderAta.toString()); console.log("Recipient Token Account:", recipientAta.toString()); // ============================================================================= // Sponsored Token Payment Demo // ============================================================================= // Create instruction to transfer tokens from sender to recipient // Transferring 250,000 base units = 0.25 tokens (with 6 decimals) const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender, // Pass signer, not just address amount: 250\_000n // 0.25 tokens }); // Prepare and send transaction with sponsor as fee payer using @solana/client // The sponsor pays transaction fees, sender signs for the transfer const signature \= await client.transaction.prepareAndSend({ authority: sender, // Sender signs the transfer instruction feePayer: sponsor, // Sponsor pays the transaction fees (different account) instructions: \[transferInstruction\], version: 0 }); console.log("\\n\=== Sponsored Token Payment Complete ==="); console.log("Transaction Signature:", signature.toString()); // Fetch final token account balances using @solana/client SPL token helper const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); console.log("\\nSender Token Account Balance:", senderBalance); console.log("Recipient Token Account Balance:", recipientBalance); // Fetch transaction details const transaction \= await client.runtime.rpc .getTransaction(signature, { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }) .send(); const feePayer \= transaction?.transaction.message.accountKeys?.\[0\]; console.log("\\nNote: The first account in accountKeys is always the fee payer"); console.log("Fee Payer Address:", feePayer); // ============================================================================= // Demo Setup Helper Function // ============================================================================= Console RunClick to execute the code. Demo // Click ">" icon on left to expand demo imports // Generate keypairs for sender, recipient, and sponsor (fee payer) const sender \= (await generateKeypair()).signer; const recipient \= (await generateKeypair()).signer; const sponsor \= (await generateKeypair()).signer; console.log("Sender Address:", sender.address); console.log("Recipient Address:", recipient.address); console.log("Sponsor Address (Fee Payer):", sponsor.address); // Demo Setup: Create client, mint account, token accounts, and fund with initial tokens const { client, mint } \= await demoSetup(sender, recipient, sponsor); console.log("\\nMint Address:", mint.address); // Derive the Associated Token Accounts addresses (ATAs) for sender and recipient const \[senderAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: sender.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); const \[recipientAta\] \= await findAssociatedTokenPda({ mint: mint.address, owner: recipient.address, tokenProgram: TOKEN\_2022\_PROGRAM\_ADDRESS }); console.log("Sender Token Account:", senderAta.toString()); console.log("Recipient Token Account:", recipientAta.toString()); // ============================================================================= // Sponsored Token Payment Demo // ============================================================================= // Create instruction to transfer tokens from sender to recipient // Transferring 250,000 base units = 0.25 tokens (with 6 decimals) const transferInstruction \= getTransferInstruction({ source: senderAta, destination: recipientAta, authority: sender, // Pass signer, not just address amount: 250\_000n // 0.25 tokens }); // Prepare and send transaction with sponsor as fee payer using @solana/client // The sponsor pays transaction fees, sender signs for the transfer const signature \= await client.transaction.prepareAndSend({ authority: sender, // Sender signs the transfer instruction feePayer: sponsor, // Sponsor pays the transaction fees (different account) instructions: \[transferInstruction\], version: 0 }); console.log("\\n\=== Sponsored Token Payment Complete ==="); console.log("Transaction Signature:", signature.toString()); // Fetch final token account balances using @solana/client SPL token helper const splToken \= client.splToken({ mint: mint.address, tokenProgram: "auto" }); const senderBalance \= await splToken.fetchBalance(sender.address); const recipientBalance \= await splToken.fetchBalance(recipient.address); console.log("\\nSender Token Account Balance:", senderBalance); console.log("Recipient Token Account Balance:", recipientBalance); // Fetch transaction details const transaction \= await client.runtime.rpc .getTransaction(signature, { encoding: "jsonParsed", maxSupportedTransactionVersion: 0 }) .send(); const feePayer \= transaction?.transaction.message.accountKeys?.\[0\]; console.log("\\nNote: The first account in accountKeys is always the fee payer"); console.log("Fee Payer Address:", feePayer); // ============================================================================= // Demo Setup Helper Function // ============================================================================= Console RunClick to execute the code. When you create a token account for an end user, they can close it and reclaim the SOL used for rent. Consider charging users for account creation in stablecoins, or factor this cost into your product economics. [Fee Abstraction at Scale with Kora](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#fee-abstraction-at-scale-with-kora) ----------------------------------------------------------------------------------------------------------------------------------------------------------- The fee payer primitive is powerful, but building a production gasless system requires more: managing sponsor wallets, handling token conversions (so users can "pay" fees in USDC), rate limiting, and security controls. [Kora](https://launch.solana.com/products/kora) handles this complexity. It's a JSON-RPC server that provides fee abstraction so users never need SOL. You can fully sponsor fees or accept fee payment in any token. Deploy Kora with a single command: cargo install kora-cli kora \--config path/to/kora.toml rpc start \--signers-config path/to/signers.toml Then use the Kora client to sign and send transactions: pnpm add @solana/kora import { KoraClient } from "@solana/kora"; const kora \= new KoraClient({ rpcUrl: "https://your-kora-instance" }); const { signature } \= await kora.signAndSendTransaction({ transaction: base64EncodedTransaction }); ### [Kora Resources](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#kora-resources) [### Kora Quick Start\ \ Get Kora running locally in minutes.](https://launch.solana.com/docs/kora/getting-started/quick-start) [### Full Transaction Demo\ \ Complete fee abstraction transaction implementation guide.](https://launch.solana.com/docs/kora/guides/full-demo) [### API Reference\ \ JSON-RPC methods and SDK documentation.](https://launch.solana.com/docs/kora/json-rpc-api) [### Node Operator Guide\ \ Deploy and configure your own Kora instance.](https://launch.solana.com/docs/kora/operators) Is this page helpful? [Previous\ \ Batch Payments](https://solana.com/docs/payments/send-payments/payment-processing/batch-payments) [Next\ \ Verify Address](https://solana.com/docs/payments/send-payments/verify-address) ### Table of Contents [How Fee Sponsorship Works](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#how-fee-sponsorship-works) [Demo](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#demo) [Fee Abstraction at Scale with Kora](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#fee-abstraction-at-scale-with-kora) [Kora Resources](https://solana.com/docs/payments/send-payments/payment-processing/fee-abstraction#kora-resources) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/payments/send-payments/payment-processing/fee-abstraction.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Create a Token Mint | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Create a Token Mint](https://solana.com/docs/tokens/basics/create-mint) ========================================================================= Copy MarkdownOpen [What's a Mint Account?](https://solana.com/docs/tokens/basics/create-mint#whats-a-mint-account) ------------------------------------------------------------------------------------------------- A mint account uniquely represents a token on Solana and stores its global metadata. Mint Account Type /// Mint data. #\[repr(C)\] #\[derive(Clone, Copy, Debug, Default, PartialEq)\] pub struct Mint { /// Optional authority used to mint new tokens. The mint authority may only /// be provided during mint creation. If no mint authority is present /// then the mint has a fixed supply and no further tokens may be /// minted. pub mint\_authority: COption, /// Total supply of tokens. pub supply: u64, /// Number of base 10 digits to the right of the decimal place. pub decimals: u8, /// Is \`true\` if this structure has been initialized pub is\_initialized: bool, /// Optional authority to freeze token accounts. pub freeze\_authority: COption, } Note that both the [Token Program](https://github.com/solana-program/token/blob/6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a/program/src/state.rs#L13-L30) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/state.rs#L25-L42) share the same base implementation for the Mint account. Every token on Solana has a mint account, and the mint's address serves as the token's unique identifier. For example, USD Coin (USDC) has the mint address `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`. This address uniquely identifies USDC throughout the Solana ecosystem. You can view this mint on [Solana Explorer](https://explorer.solana.com/address/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) . [How to Create a Mint Account](https://solana.com/docs/tokens/basics/create-mint#how-to-create-a-mint-account) --------------------------------------------------------------------------------------------------------------- Creating a mint account requires the [`InitializeMint`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L37) instruction. See the [implementation details here](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/processor.rs#L27) . You need invoke two instructions to create a mint account: 1. System Program: Create an account with allocated space for a mint account and transfer ownership to the Token Program. 2. Token Program: Initialize the mint account data ### [Typescript](https://solana.com/docs/tokens/basics/create-mint#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and mint keypair) const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address); console.log("\\nTransaction Signature:", transactionSignature); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and mint keypair) const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address); console.log("\\nTransaction Signature:", transactionSignature); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/create-mint#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_token\_interface::{id as token\_program\_id, instruction::initialize\_mint, state::Mint}; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); let space \= Mint::LEN; let rent \= client.get\_minimum\_balance\_for\_rent\_exemption(space).await?; // Create account instruction let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), &mint.pubkey(), rent, space as u64, &token\_program\_id(), ); // Initialize mint instruction let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint address &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 9, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_account\_instruction, initialize\_mint\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; println!("Mint Address: {}", mint.pubkey()); println!("\\nTransaction Signature: {}", transaction\_signature); let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint \= Mint::unpack(&mint\_account.data)?; println!("\\n{:#?}", mint); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_token\_interface::{id as token\_program\_id, instruction::initialize\_mint, state::Mint}; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); let space \= Mint::LEN; let rent \= client.get\_minimum\_balance\_for\_rent\_exemption(space).await?; // Create account instruction let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), &mint.pubkey(), rent, space as u64, &token\_program\_id(), ); // Initialize mint instruction let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint address &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 9, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_account\_instruction, initialize\_mint\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; println!("Mint Address: {}", mint.pubkey()); println!("\\nTransaction Signature: {}", transaction\_signature); let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint \= Mint::unpack(&mint\_account.data)?; println!("\\n{:#?}", mint); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/create-mint#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import create\_account, CreateAccountParams from spl.token.instructions import initialize\_mint, InitializeMintParams from spl.token.constants import TOKEN\_PROGRAM\_ID \# Constants DECIMALS \= 9 async def create\_mint(rpc, mint\_authority): """ Creates and initializes a new mint account """ mint \= Keypair() space \= 82 \# getMintSize() equivalent for SPL Token \# Get minimum balance for rent exemption rent \= await rpc.get\_minimum\_balance\_for\_rent\_exemption(space) \# Create & initialize mint account create\_account\_instruction \= create\_account( CreateAccountParams( from\_pubkey\=mint\_authority.pubkey(), to\_pubkey\=mint.pubkey(), lamports\=rent.value, space\=space, owner\=TOKEN\_PROGRAM\_ID ) ) initialize\_mint\_instruction \= initialize\_mint( InitializeMintParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), decimals\=DECIMALS, mint\_authority\=mint\_authority.pubkey(), freeze\_authority\=None ) ) instructions \= \[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction\ \ \] \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority, mint\]) print("Mint account created successfully") print(f"Mint: {mint.pubkey()}") print(f"Mint Authority: {mint\_authority.pubkey()}") print(f"Decimals: {DECIMALS}") return mint.pubkey() async def main(): rpc \= AsyncClient("http://localhost:8899") \# Constants mint\_authority \= Keypair() async with rpc: \# Create mint account await create\_mint(rpc, mint\_authority) if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import create\_account, CreateAccountParams from spl.token.instructions import initialize\_mint, InitializeMintParams from spl.token.constants import TOKEN\_PROGRAM\_ID \# Constants DECIMALS \= 9 async def create\_mint(rpc, mint\_authority): """ Creates and initializes a new mint account """ mint \= Keypair() space \= 82 \# getMintSize() equivalent for SPL Token \# Get minimum balance for rent exemption rent \= await rpc.get\_minimum\_balance\_for\_rent\_exemption(space) \# Create & initialize mint account create\_account\_instruction \= create\_account( CreateAccountParams( from\_pubkey\=mint\_authority.pubkey(), to\_pubkey\=mint.pubkey(), lamports\=rent.value, space\=space, owner\=TOKEN\_PROGRAM\_ID ) ) initialize\_mint\_instruction \= initialize\_mint( InitializeMintParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), decimals\=DECIMALS, mint\_authority\=mint\_authority.pubkey(), freeze\_authority\=None ) ) instructions \= \[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction\ \ \] \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority, mint\]) print("Mint account created successfully") print(f"Mint: {mint.pubkey()}") print(f"Mint Authority: {mint\_authority.pubkey()}") print(f"Decimals: {DECIMALS}") return mint.pubkey() async def main(): rpc \= AsyncClient("http://localhost:8899") \# Constants mint\_authority \= Keypair() async with rpc: \# Create mint account await create\_mint(rpc, mint\_authority) if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ SPL Token Basics](https://solana.com/docs/tokens/basics) [Next\ \ Create a Token Account](https://solana.com/docs/tokens/basics/create-token-account) ### Table of Contents [What's a Mint Account?](https://solana.com/docs/tokens/basics/create-mint#whats-a-mint-account) [How to Create a Mint Account](https://solana.com/docs/tokens/basics/create-mint#how-to-create-a-mint-account) [Typescript](https://solana.com/docs/tokens/basics/create-mint#typescript) [Rust](https://solana.com/docs/tokens/basics/create-mint#rust) [Python](https://solana.com/docs/tokens/basics/create-mint#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/create-mint.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Sync Native | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Sync Native](https://solana.com/docs/tokens/basics/sync-native) ================================================================= Copy MarkdownOpen [Sync Native SOL](https://solana.com/docs/tokens/basics/sync-native#sync-native-sol) ------------------------------------------------------------------------------------- Wrapped SOL (WSOL) is a token account that tracks the amount of lamports in the account as the token balance. WSOL enables integration with DeFi protocols to transfer SOL as an SPL token. The [`SyncNative`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/interface/src/instruction.rs#L387) instruction synchronizes a wrapped SOL (WSOL) token account balance with the actual SOL (lamports) stored in it. When you transfer native SOL to a WSOL token account, the token balance doesn't automatically update. You must call SyncNative to reflect the correct WSOL balance. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/interface/src/instruction.rs#L387) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L182) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/sync-native#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners, address } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getSyncNativeInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(2\_000\_000\_000n), commitment: "confirmed" }); // Native mint (Wrapped SOL) address const NATIVE\_MINT \= address("So11111111111111111111111111111111111111112"); // Use findAssociatedTokenPda to derive the ATA address for WSOL const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: NATIVE\_MINT, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to create the WSOL associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: NATIVE\_MINT, owner: feePayer.address }); // Amount to wrap (1 SOL = 1,000,000,000 lamports) const amountToSync \= 1\_000\_000\_000n; // Create instruction to transfer SOL to the WSOL token account const transferSolInstruction \= getTransferSolInstruction({ source: feePayer, destination: associatedTokenAddress, amount: amountToSync }); // Create instruction to sync native SOL balance with WSOL token balance const syncNativeInstruction \= getSyncNativeInstruction({ account: associatedTokenAddress }); const instructions \= \[\ \ createAtaInstruction,\ \ transferSolInstruction,\ \ syncNativeInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Fee Payer Address:", feePayer.address.toString()); console.log("WSOL Token Account Address:", associatedTokenAddress.toString()); console.log("Successfully wrapped 1.0 SOL into WSOL"); console.log("Transaction Signature:", transactionSignature); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners, address } from "@solana/kit"; import { getTransferSolInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getSyncNativeInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(2\_000\_000\_000n), commitment: "confirmed" }); // Native mint (Wrapped SOL) address const NATIVE\_MINT \= address("So11111111111111111111111111111111111111112"); // Use findAssociatedTokenPda to derive the ATA address for WSOL const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: NATIVE\_MINT, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to create the WSOL associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: NATIVE\_MINT, owner: feePayer.address }); // Amount to wrap (1 SOL = 1,000,000,000 lamports) const amountToSync \= 1\_000\_000\_000n; // Create instruction to transfer SOL to the WSOL token account const transferSolInstruction \= getTransferSolInstruction({ source: feePayer, destination: associatedTokenAddress, amount: amountToSync }); // Create instruction to sync native SOL balance with WSOL token balance const syncNativeInstruction \= getSyncNativeInstruction({ account: associatedTokenAddress }); const instructions \= \[\ \ createAtaInstruction,\ \ transferSolInstruction,\ \ syncNativeInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Fee Payer Address:", feePayer.address.toString()); console.log("WSOL Token Account Address:", associatedTokenAddress.toString()); console.log("Successfully wrapped 1.0 SOL into WSOL"); console.log("Transaction Signature:", transactionSignature); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/sync-native#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::transfer; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::sync\_native, native\_mint::ID as NATIVE\_MINT\_ID, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 2 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 2\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Get associated token account address for WSOL let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &NATIVE\_MINT\_ID, // mint (Wrapped SOL) ); // Instruction to create associated token account for WSOL let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &NATIVE\_MINT\_ID, // mint address &token\_program\_id(), // program id ); // Amount to wrap (1 SOL = 1,000,000,000 lamports) let amount \= 1\_000\_000\_000; // Create transfer instruction to send SOL to the WSOL token account let transfer\_instruction \= transfer(&fee\_payer.pubkey(), &associated\_token\_address, amount); // Create sync native instruction to update WSOL balance let sync\_native\_instruction \= sync\_native(&token\_program\_id(), &associated\_token\_address)?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_ata\_instruction,\ \ transfer\_instruction,\ \ sync\_native\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; println!("WSOL Token Account Address: {}", associated\_token\_address); if let Some(token\_account) \= token\_account { println!("{:#?}", token\_account); } Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::transfer; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::sync\_native, native\_mint::ID as NATIVE\_MINT\_ID, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 2 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 2\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Get associated token account address for WSOL let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &NATIVE\_MINT\_ID, // mint (Wrapped SOL) ); // Instruction to create associated token account for WSOL let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &NATIVE\_MINT\_ID, // mint address &token\_program\_id(), // program id ); // Amount to wrap (1 SOL = 1,000,000,000 lamports) let amount \= 1\_000\_000\_000; // Create transfer instruction to send SOL to the WSOL token account let transfer\_instruction \= transfer(&fee\_payer.pubkey(), &associated\_token\_address, amount); // Create sync native instruction to update WSOL balance let sync\_native\_instruction \= sync\_native(&token\_program\_id(), &associated\_token\_address)?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_ata\_instruction,\ \ transfer\_instruction,\ \ sync\_native\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; println!("WSOL Token Account Address: {}", associated\_token\_address); if let Some(token\_account) \= token\_account { println!("{:#?}", token\_account); } Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/sync-native#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import transfer, TransferParams from spl.token.instructions import ( create\_associated\_token\_account, sync\_native, SyncNativeParams, close\_account, CloseAccountParams, get\_associated\_token\_address ) from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID from solders.pubkey import Pubkey \# Native mint address for wrapped SOL NATIVE\_MINT \= Pubkey.from\_string("So11111111111111111111111111111111111111112") async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs payer \= Keypair() owner \= Keypair() \# Amount to wrap (in lamports) amount\_to\_wrap \= 1000000000 \# 1 SOL async with rpc: \# Get associated token address for wrapped SOL wrapped\_sol\_account \= get\_associated\_token\_address( owner\=owner.pubkey(), mint\=NATIVE\_MINT, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Create associated token account for wrapped SOL create\_ata\_instruction \= create\_associated\_token\_account( payer\=payer.pubkey(), owner\=owner.pubkey(), mint\=NATIVE\_MINT ) \# Transfer SOL to the wrapped SOL account transfer\_instruction \= transfer( TransferParams( from\_pubkey\=payer.pubkey(), to\_pubkey\=wrapped\_sol\_account, lamports\=amount\_to\_wrap ) ) \# Sync native instruction to update the wrapped SOL balance sync\_native\_instruction \= sync\_native( SyncNativeParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=wrapped\_sol\_account ) ) instructions \= \[\ \ create\_ata\_instruction,\ \ transfer\_instruction,\ \ sync\_native\_instruction\ \ \] \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer\]) print(f"Wrapped SOL Operations:") print(f"Owner: {owner.pubkey()}") print(f"Wrapped SOL Account: {wrapped\_sol\_account}") print(f"Amount to wrap: {amount\_to\_wrap} lamports ({amount\_to\_wrap / 1e9} SOL)") print(f"Native Mint: {NATIVE\_MINT}") print(f"Payer: {payer.pubkey()}") print(f"Wrapped SOL transaction created successfully") async def unwrap\_sol\_example(): """Example of unwrapping SOL (closing wrapped SOL account)""" rpc \= AsyncClient("http://localhost:8899") payer \= Keypair() owner \= Keypair() async with rpc: \# Get wrapped SOL account wrapped\_sol\_account \= get\_associated\_token\_address( owner\=owner.pubkey(), mint\=NATIVE\_MINT, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Close account instruction (unwraps SOL) close\_account\_instruction \= close\_account( CloseAccountParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=wrapped\_sol\_account, dest\=owner.pubkey(), \# SOL will be sent back to owner owner\=owner.pubkey() ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[close\_account\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"\\nUnwrap SOL Example:") print(f"Wrapped SOL Account: {wrapped\_sol\_account}") print(f"Owner: {owner.pubkey()}") print(f"Destination: {owner.pubkey()}") print(f"Unwrap SOL transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) asyncio.run(unwrap\_sol\_example()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import transfer, TransferParams from spl.token.instructions import ( create\_associated\_token\_account, sync\_native, SyncNativeParams, close\_account, CloseAccountParams, get\_associated\_token\_address ) from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID from solders.pubkey import Pubkey \# Native mint address for wrapped SOL NATIVE\_MINT \= Pubkey.from\_string("So11111111111111111111111111111111111111112") async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs payer \= Keypair() owner \= Keypair() \# Amount to wrap (in lamports) amount\_to\_wrap \= 1000000000 \# 1 SOL async with rpc: \# Get associated token address for wrapped SOL wrapped\_sol\_account \= get\_associated\_token\_address( owner\=owner.pubkey(), mint\=NATIVE\_MINT, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Create associated token account for wrapped SOL create\_ata\_instruction \= create\_associated\_token\_account( payer\=payer.pubkey(), owner\=owner.pubkey(), mint\=NATIVE\_MINT ) \# Transfer SOL to the wrapped SOL account transfer\_instruction \= transfer( TransferParams( from\_pubkey\=payer.pubkey(), to\_pubkey\=wrapped\_sol\_account, lamports\=amount\_to\_wrap ) ) \# Sync native instruction to update the wrapped SOL balance sync\_native\_instruction \= sync\_native( SyncNativeParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=wrapped\_sol\_account ) ) instructions \= \[\ \ create\_ata\_instruction,\ \ transfer\_instruction,\ \ sync\_native\_instruction\ \ \] \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer\]) print(f"Wrapped SOL Operations:") print(f"Owner: {owner.pubkey()}") print(f"Wrapped SOL Account: {wrapped\_sol\_account}") print(f"Amount to wrap: {amount\_to\_wrap} lamports ({amount\_to\_wrap / 1e9} SOL)") print(f"Native Mint: {NATIVE\_MINT}") print(f"Payer: {payer.pubkey()}") print(f"Wrapped SOL transaction created successfully") async def unwrap\_sol\_example(): """Example of unwrapping SOL (closing wrapped SOL account)""" rpc \= AsyncClient("http://localhost:8899") payer \= Keypair() owner \= Keypair() async with rpc: \# Get wrapped SOL account wrapped\_sol\_account \= get\_associated\_token\_address( owner\=owner.pubkey(), mint\=NATIVE\_MINT, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Close account instruction (unwraps SOL) close\_account\_instruction \= close\_account( CloseAccountParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=wrapped\_sol\_account, dest\=owner.pubkey(), \# SOL will be sent back to owner owner\=owner.pubkey() ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[close\_account\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"\\nUnwrap SOL Example:") print(f"Wrapped SOL Account: {wrapped\_sol\_account}") print(f"Owner: {owner.pubkey()}") print(f"Destination: {owner.pubkey()}") print(f"Unwrap SOL transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) asyncio.run(unwrap\_sol\_example()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Burn Tokens](https://solana.com/docs/tokens/basics/burn-tokens) [Next\ \ Close Token Account](https://solana.com/docs/tokens/basics/close-account) ### Table of Contents [Sync Native SOL](https://solana.com/docs/tokens/basics/sync-native#sync-native-sol) [Typescript](https://solana.com/docs/tokens/basics/sync-native#typescript) [Rust](https://solana.com/docs/tokens/basics/sync-native#rust) [Python](https://solana.com/docs/tokens/basics/sync-native#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/sync-native.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Mint Tokens | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Mint Tokens](https://solana.com/docs/tokens/basics/mint-tokens) ================================================================= Copy MarkdownOpen [How to Mint Tokens](https://solana.com/docs/tokens/basics/mint-tokens#how-to-mint-tokens) ------------------------------------------------------------------------------------------- Minting creates new units of a token using the [`MintTo`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L174) instruction. * Only the mint authority can mint new tokens * A destination token account must exist to receive the minted tokens The [Token Program](https://github.com/solana-program/token/blob/3daf44899f0bd71c879d28dffdfb788dd944f3c5/program/src/processor.rs#L521) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/processor.rs#L973) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/mint-tokens#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); console.log("Mint Address:", mint.address); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); console.log( "Associated Token Account Address: ", associatedTokenAddress.toString() ); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 100n // 1.00 tokens with 2 decimals }); // Create transaction message for minting tokens const mintTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[mintToInstruction\], tx) ); // Sign transaction message with all required signers const signedMintTx \= await signTransactionMessageWithSigners(mintTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedMintTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedMintTx); console.log("Successfully minted 1.0 tokens"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); console.log("Mint Address:", mint.address); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); console.log( "Associated Token Account Address: ", associatedTokenAddress.toString() ); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 100n // 1.00 tokens with 2 decimals }); // Create transaction message for minting tokens const mintTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[mintToInstruction\], tx) ); // Sign transaction message with all required signers const signedMintTx \= await signTransactionMessageWithSigners(mintTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedMintTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedMintTx); console.log("Successfully minted 1.0 tokens"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/mint-tokens#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address\_with\_program\_id, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{initialize\_mint, mint\_to}, state::{Account, Mint}, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address\_with\_program\_id( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint &token\_program\_id(), // program\_id ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Amount of tokens to mint (100 tokens with 2 decimal places) let amount \= 100; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction for minting tokens let transaction \= Transaction::new\_signed\_with\_payer( &\[mint\_to\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; let token \= client.get\_account(&associated\_token\_address).await?; let token\_data \= Account::unpack(&token.data)?; println!("Minted 1.00 tokens to the associated token account"); println!("\\nMint Address: {}", mint.pubkey()); println!("{:#?}", mint\_data); println!( "\\nAssociated Token Account Address: {}", associated\_token\_address ); println!("{:#?}", token\_data); println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address\_with\_program\_id, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{initialize\_mint, mint\_to}, state::{Account, Mint}, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address\_with\_program\_id( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint &token\_program\_id(), // program\_id ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Amount of tokens to mint (100 tokens with 2 decimal places) let amount \= 100; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction for minting tokens let transaction \= Transaction::new\_signed\_with\_payer( &\[mint\_to\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; let token \= client.get\_account(&associated\_token\_address).await?; let token\_data \= Account::unpack(&token.data)?; println!("Minted 1.00 tokens to the associated token account"); println!("\\nMint Address: {}", mint.pubkey()); println!("{:#?}", mint\_data); println!( "\\nAssociated Token Account Address: {}", associated\_token\_address ); println!("{:#?}", token\_data); println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/mint-tokens#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import mint\_to, MintToParams from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() mint\_authority \= Keypair() mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") destination\_token\_account \= Pubkey.from\_string("GfVPzUxMDvhFJ1Xs6C9i47XQRSapTd8LHw5grGuTquyQ") \# Amount to mint (in smallest unit) amount\_to\_mint \= 1000000000 \# 1 token with 9 decimals async with rpc: \# Create mint instruction mint\_instruction \= mint\_to( MintToParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint\_address, dest\=destination\_token\_account, mint\_authority\=mint\_authority.pubkey(), amount\=amount\_to\_mint ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[mint\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, mint\_authority\]) print(f"Mint: {mint\_address}") print(f"Destination: {destination\_token\_account}") print(f"Amount: {amount\_to\_mint}") print(f"Mint authority: {mint\_authority.pubkey()}") print(f"Payer: {payer.pubkey()}") print(f"Mint transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import mint\_to, MintToParams from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() mint\_authority \= Keypair() mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") destination\_token\_account \= Pubkey.from\_string("GfVPzUxMDvhFJ1Xs6C9i47XQRSapTd8LHw5grGuTquyQ") \# Amount to mint (in smallest unit) amount\_to\_mint \= 1000000000 \# 1 token with 9 decimals async with rpc: \# Create mint instruction mint\_instruction \= mint\_to( MintToParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint\_address, dest\=destination\_token\_account, mint\_authority\=mint\_authority.pubkey(), amount\=amount\_to\_mint ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[mint\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, mint\_authority\]) print(f"Mint: {mint\_address}") print(f"Destination: {destination\_token\_account}") print(f"Amount: {amount\_to\_mint}") print(f"Mint authority: {mint\_authority.pubkey()}") print(f"Payer: {payer.pubkey()}") print(f"Mint transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Create a Token Account](https://solana.com/docs/tokens/basics/create-token-account) [Next\ \ Transfer Tokens](https://solana.com/docs/tokens/basics/transfer-tokens) ### Table of Contents [How to Mint Tokens](https://solana.com/docs/tokens/basics/mint-tokens#how-to-mint-tokens) [Typescript](https://solana.com/docs/tokens/basics/mint-tokens#typescript) [Rust](https://solana.com/docs/tokens/basics/mint-tokens#rust) [Python](https://solana.com/docs/tokens/basics/mint-tokens#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/mint-tokens.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Freeze Account | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Freeze Account](https://solana.com/docs/tokens/basics/freeze-account) ======================================================================= Copy MarkdownOpen [Freeze Account](https://solana.com/docs/tokens/basics/freeze-account#freeze-account) -------------------------------------------------------------------------------------- The [`FreezeAccount`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L228) instruction prevents all token transfers or token burns from a specific token account. Once frozen, the account cannot send tokens, receive tokens, or be closed until it is thawed. Only the freeze authority of the token's mint can freeze accounts. If the freeze authority is revoked (set to null) on the mint account, tokens can never be frozen. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L228) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L291) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/freeze-account#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getFreezeAccountInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address, freezeAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1000.0 tokens"); // Get a fresh blockhash for the freeze transaction const { value: freezeBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to freeze the token account const freezeInstruction \= getFreezeAccountInstruction({ account: associatedTokenAddress, mint: mint.address, owner: feePayer.address }); // Create transaction message for freezing const freezeTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(freezeBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[freezeInstruction\], tx) ); // Sign transaction message with all required signers const signedFreezeTx \= await signTransactionMessageWithSigners(freezeTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedFreezeTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedFreezeTx); console.log("\\nSuccessfully frozen the token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getFreezeAccountInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address, freezeAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1000.0 tokens"); // Get a fresh blockhash for the freeze transaction const { value: freezeBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to freeze the token account const freezeInstruction \= getFreezeAccountInstruction({ account: associatedTokenAddress, mint: mint.address, owner: feePayer.address }); // Create transaction message for freezing const freezeTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(freezeBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[freezeInstruction\], tx) ); // Sign transaction message with all required signers const signedFreezeTx \= await signTransactionMessageWithSigners(freezeTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedFreezeTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedFreezeTx); console.log("\\nSuccessfully frozen the token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/freeze-account#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{freeze\_account, initialize\_mint, mint\_to, transfer\_checked}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Set decimals for mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Create freeze account instruction let freeze\_instruction \= freeze\_account( &token\_program\_id(), // program id &associated\_token\_address, // token account to freeze &mint.pubkey(), // mint &fee\_payer.pubkey(), // freeze authority &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction for freezing token account let transaction \= Transaction::new\_signed\_with\_payer( &\[freeze\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; println!("Token Account Address: {}", associated\_token\_address); let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!("{:#?}", token\_account); } // Self token transfer to demonstrate failure with frozen token account let transfer\_instruction \= transfer\_checked( &token\_program\_id(), // program id &associated\_token\_address, // source &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signers amount, // amount decimals, // decimals )?; let transaction \= Transaction::new\_signed\_with\_payer( &\[transfer\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); println!("\\nTransfer Expect to Fail with Frozen Token Account"); match client.send\_and\_confirm\_transaction(&transaction).await { Ok(\_) \=> println!("Transaction successful"), Err(e) \=> println!("{:#?}", e), } Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{freeze\_account, initialize\_mint, mint\_to, transfer\_checked}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Set decimals for mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Create freeze account instruction let freeze\_instruction \= freeze\_account( &token\_program\_id(), // program id &associated\_token\_address, // token account to freeze &mint.pubkey(), // mint &fee\_payer.pubkey(), // freeze authority &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction for freezing token account let transaction \= Transaction::new\_signed\_with\_payer( &\[freeze\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; println!("Token Account Address: {}", associated\_token\_address); let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!("{:#?}", token\_account); } // Self token transfer to demonstrate failure with frozen token account let transfer\_instruction \= transfer\_checked( &token\_program\_id(), // program id &associated\_token\_address, // source &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signers amount, // amount decimals, // decimals )?; let transaction \= Transaction::new\_signed\_with\_payer( &\[transfer\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); println!("\\nTransfer Expect to Fail with Frozen Token Account"); match client.send\_and\_confirm\_transaction(&transaction).await { Ok(\_) \=> println!("Transaction successful"), Err(e) \=> println!("{:#?}", e), } Ok(()) } Console RunClick to execute the code. Is this page helpful? [Previous\ \ Close Token Account](https://solana.com/docs/tokens/basics/close-account) [Next\ \ Thaw Account](https://solana.com/docs/tokens/basics/thaw-account) ### Table of Contents [Freeze Account](https://solana.com/docs/tokens/basics/freeze-account#freeze-account) [Typescript](https://solana.com/docs/tokens/basics/freeze-account#typescript) [Rust](https://solana.com/docs/tokens/basics/freeze-account#rust) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/freeze-account.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Freeze Account | Solana --- # Close Token Account | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Close Token Account](https://solana.com/docs/tokens/basics/close-account) =========================================================================== Copy MarkdownOpen [Close Account](https://solana.com/docs/tokens/basics/close-account#close-account) ----------------------------------------------------------------------------------- The [`CloseAccount`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L212C5-L212C17) instruction permanently closes a token account and transfers all remaining SOL (rent) to a specified destination account. The token account balance must be zero before closing. Only the token account owner or designated close authority can execute this instruction. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L212C5-L212C17) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L274) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/close-account#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getCloseAccountInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer and destination const feePayer \= await generateKeyPairSigner(); const destination \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Destination Address:", destination.address.toString()); console.log("Transaction Signature:", transactionSignature); // Get a fresh blockhash for the close transaction const { value: closeBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to close the token account const closeAccountInstruction \= getCloseAccountInstruction({ account: associatedTokenAddress, destination: destination.address, owner: feePayer }); // Create transaction message for closing const closeTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(closeBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[closeAccountInstruction\], tx) ); // Sign transaction message with all required signers const signedCloseTx \= await signTransactionMessageWithSigners(closeTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedCloseTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedCloseTx); console.log("\\nSuccessfully closed the token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getCloseAccountInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer and destination const feePayer \= await generateKeyPairSigner(); const destination \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Destination Address:", destination.address.toString()); console.log("Transaction Signature:", transactionSignature); // Get a fresh blockhash for the close transaction const { value: closeBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to close the token account const closeAccountInstruction \= getCloseAccountInstruction({ account: associatedTokenAddress, destination: destination.address, owner: feePayer }); // Create transaction message for closing const closeTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(closeBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[closeAccountInstruction\], tx) ); // Sign transaction message with all required signers const signedCloseTx \= await signTransactionMessageWithSigners(closeTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedCloseTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedCloseTx); console.log("\\nSuccessfully closed the token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/close-account#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{close\_account, initialize\_mint}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Set decimals for mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; println!( "Associated Token Account Address: {}", associated\_token\_address ); if let Some(token\_account) \= token\_account { println!("Account Created"); println!("{:#?}", token\_account); } // Create close account instruction let close\_instruction \= close\_account( &token\_program\_id(), &associated\_token\_address, // Token account to close &fee\_payer.pubkey(), // Destination to receive SOL &fee\_payer.pubkey(), // Owner of token account &\[&fee\_payer.pubkey()\], )?; // Create transaction for closing token account let transaction \= Transaction::new\_signed\_with\_payer( &\[close\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; match client.get\_account(&associated\_token\_address).await { Ok(token\_account) \=> println!("{:#?}", token\_account), Err(e) \=> eprintln!("\\nAccount Closed: \\n{:#?}", e), } Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{close\_account, initialize\_mint}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Set decimals for mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; println!( "Associated Token Account Address: {}", associated\_token\_address ); if let Some(token\_account) \= token\_account { println!("Account Created"); println!("{:#?}", token\_account); } // Create close account instruction let close\_instruction \= close\_account( &token\_program\_id(), &associated\_token\_address, // Token account to close &fee\_payer.pubkey(), // Destination to receive SOL &fee\_payer.pubkey(), // Owner of token account &\[&fee\_payer.pubkey()\], )?; // Create transaction for closing token account let transaction \= Transaction::new\_signed\_with\_payer( &\[close\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; match client.get\_account(&associated\_token\_address).await { Ok(token\_account) \=> println!("{:#?}", token\_account), Err(e) \=> eprintln!("\\nAccount Closed: \\n{:#?}", e), } Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/close-account#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import close\_account, CloseAccountParams from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() owner \= Keypair() token\_account \= Pubkey.from\_string("GfVPzUxMDvhFJ1Xs6C9i47XQRSapTd8LHw5grGuTquyQ") \# Account to receive the remaining lamports (usually the owner) destination \= owner.pubkey() async with rpc: \# Create close account instruction close\_instruction \= close\_account( CloseAccountParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=token\_account, dest\=destination, owner\=owner.pubkey() ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[close\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"Token Account: {token\_account}") print(f"Owner: {owner.pubkey()}") print(f"Destination: {destination}") print(f"Close token account transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import close\_account, CloseAccountParams from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() owner \= Keypair() token\_account \= Pubkey.from\_string("GfVPzUxMDvhFJ1Xs6C9i47XQRSapTd8LHw5grGuTquyQ") \# Account to receive the remaining lamports (usually the owner) destination \= owner.pubkey() async with rpc: \# Create close account instruction close\_instruction \= close\_account( CloseAccountParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=token\_account, dest\=destination, owner\=owner.pubkey() ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[close\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"Token Account: {token\_account}") print(f"Owner: {owner.pubkey()}") print(f"Destination: {destination}") print(f"Close token account transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Sync Native](https://solana.com/docs/tokens/basics/sync-native) [Next\ \ Freeze Account](https://solana.com/docs/tokens/basics/freeze-account) ### Table of Contents [Close Account](https://solana.com/docs/tokens/basics/close-account#close-account) [Typescript](https://solana.com/docs/tokens/basics/close-account#typescript) [Rust](https://solana.com/docs/tokens/basics/close-account#rust) [Python](https://solana.com/docs/tokens/basics/close-account#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/close-account.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Transfer Tokens | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Transfer Tokens](https://solana.com/docs/tokens/basics/transfer-tokens) ========================================================================= Copy MarkdownOpen [How to Transfer Tokens](https://solana.com/docs/tokens/basics/transfer-tokens#how-to-transfer-tokens) ------------------------------------------------------------------------------------------------------- Token transfers move tokens between token accounts of the same mint using the [`TransferChecked`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L268) instruction. * Both token accounts must hold the same token type (mint) * Only the source account owner or delegate can authorize transfers The [Token Program](https://github.com/solana-program/token/blob/3daf44899f0bd71c879d28dffdfb788dd944f3c5/program/src/processor.rs#L227) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/processor.rs#L300) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/transfer-tokens#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getTransferInstruction, fetchToken } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer (sender) and recipient const feePayer \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); console.log("Fee Payer/Sender Address:", feePayer.address.toString()); console.log("Recipient Address:", recipient.address.toString()); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); console.log("Mint Address:", mint.address.toString()); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); // Derive the ATAs for sender and recipient const \[senderAssociatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); const \[recipientAssociatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: recipient.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); console.log( "Sender Associated Token Account Address:", senderAssociatedTokenAddress.toString() ); console.log( "Recipient Associated Token Account Address:", recipientAssociatedTokenAddress.toString() ); // Create instruction for sender's ATA const createSenderAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction for recipient's ATA const createRecipientAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: recipient.address }); // Create instruction to mint tokens to sender const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: senderAssociatedTokenAddress, mintAuthority: feePayer.address, amount: 100n }); // Combine all instructions in order const instructions \= \[\ \ createAccountInstruction, // Create mint account\ \ initializeMintInstruction, // Initialize mint\ \ createSenderAtaInstruction, // Create sender's ATA\ \ createRecipientAtaInstruction, // Create recipient's ATA\ \ mintToInstruction // Mint tokens to sender\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1.0 tokens"); // Get a fresh blockhash for the transfer transaction const { value: transferBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to transfer tokens const transferInstruction \= getTransferInstruction({ source: senderAssociatedTokenAddress, destination: recipientAssociatedTokenAddress, authority: feePayer.address, amount: 50n // 0.50 tokens with 2 decimals }); // Create transaction message for token transfer const transferTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(transferBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[transferInstruction\], tx) ); // Sign transaction message with all required signers const signedTransferTx \= await signTransactionMessageWithSigners(transferTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransferTx, { commitment: "confirmed" } ); // Get transaction signature const transferTransactionSignature \= getSignatureFromTransaction(signedTransferTx); console.log("Transaction Signature:", transferTransactionSignature); console.log("Successfully transferred 0.5 tokens"); const senderTokenAccount \= await fetchToken(rpc, senderAssociatedTokenAddress, { commitment: "confirmed" }); const recipientTokenAccount \= await fetchToken( rpc, recipientAssociatedTokenAddress, { commitment: "confirmed" } ); const senderBalance \= senderTokenAccount.data.amount; const recipientBalance \= recipientTokenAccount.data.amount; console.log("=== Final Balances ==="); console.log("Sender balance:", Number(senderBalance) / 100, "tokens"); console.log("Recipient balance:", Number(recipientBalance) / 100, "tokens"); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getTransferInstruction, fetchToken } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer (sender) and recipient const feePayer \= await generateKeyPairSigner(); const recipient \= await generateKeyPairSigner(); console.log("Fee Payer/Sender Address:", feePayer.address.toString()); console.log("Recipient Address:", recipient.address.toString()); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); console.log("Mint Address:", mint.address.toString()); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); // Derive the ATAs for sender and recipient const \[senderAssociatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); const \[recipientAssociatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: recipient.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); console.log( "Sender Associated Token Account Address:", senderAssociatedTokenAddress.toString() ); console.log( "Recipient Associated Token Account Address:", recipientAssociatedTokenAddress.toString() ); // Create instruction for sender's ATA const createSenderAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction for recipient's ATA const createRecipientAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: recipient.address }); // Create instruction to mint tokens to sender const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: senderAssociatedTokenAddress, mintAuthority: feePayer.address, amount: 100n }); // Combine all instructions in order const instructions \= \[\ \ createAccountInstruction, // Create mint account\ \ initializeMintInstruction, // Initialize mint\ \ createSenderAtaInstruction, // Create sender's ATA\ \ createRecipientAtaInstruction, // Create recipient's ATA\ \ mintToInstruction // Mint tokens to sender\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1.0 tokens"); // Get a fresh blockhash for the transfer transaction const { value: transferBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to transfer tokens const transferInstruction \= getTransferInstruction({ source: senderAssociatedTokenAddress, destination: recipientAssociatedTokenAddress, authority: feePayer.address, amount: 50n // 0.50 tokens with 2 decimals }); // Create transaction message for token transfer const transferTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(transferBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[transferInstruction\], tx) ); // Sign transaction message with all required signers const signedTransferTx \= await signTransactionMessageWithSigners(transferTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransferTx, { commitment: "confirmed" } ); // Get transaction signature const transferTransactionSignature \= getSignatureFromTransaction(signedTransferTx); console.log("Transaction Signature:", transferTransactionSignature); console.log("Successfully transferred 0.5 tokens"); const senderTokenAccount \= await fetchToken(rpc, senderAssociatedTokenAddress, { commitment: "confirmed" }); const recipientTokenAccount \= await fetchToken( rpc, recipientAssociatedTokenAddress, { commitment: "confirmed" } ); const senderBalance \= senderTokenAccount.data.amount; const recipientBalance \= recipientTokenAccount.data.amount; console.log("=== Final Balances ==="); console.log("Sender balance:", Number(senderBalance) / 100, "tokens"); console.log("Recipient balance:", Number(recipientBalance) / 100, "tokens"); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/transfer-tokens#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{initialize\_mint, mint\_to, transfer\_checked}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Generate a second keypair for the token recipient let recipient \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Airdrop 1 SOL to recipient for rent exemption let recipient\_airdrop\_signature \= client .request\_airdrop(&recipient.pubkey(), 1\_000\_000\_000) .await?; client .confirm\_transaction(&recipient\_airdrop\_signature) .await?; loop { let confirmed \= client .confirm\_transaction(&recipient\_airdrop\_signature) .await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Calculate the associated token account address for fee\_payer let source\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account for fee\_payer let create\_source\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Calculate the associated token account address for recipient let destination\_token\_address \= get\_associated\_token\_address( &recipient.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account for recipient let create\_destination\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &recipient.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimal places) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the source token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &source\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_source\_ata\_instruction,\ \ create\_destination\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Amount of tokens to transfer (0.50 tokens with 2 decimals) let transfer\_amount \= 50; // Create transfer\_checked instruction to send tokens from source to destination let transfer\_instruction \= transfer\_checked( &token\_program\_id(), // program id &source\_token\_address, // source &mint.pubkey(), // mint &destination\_token\_address, // destination &fee\_payer.pubkey(), // owner of source &\[&fee\_payer.pubkey()\], // signers transfer\_amount, // amount 2, // decimals )?; // Create transaction for transferring tokens let transaction \= Transaction::new\_signed\_with\_payer( &\[transfer\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; // Get token account balances to verify the transfer let source\_token\_account \= client.get\_token\_account(&source\_token\_address).await?; let destination\_token\_account \= client.get\_token\_account(&destination\_token\_address).await?; println!("Successfully transferred 0.50 tokens from sender to recipient"); println!("\\nMint Address: {}", mint.pubkey()); println!("{:#?}", mint\_data); println!("\\nSource Token Account Address: {}", source\_token\_address); if let Some(source\_account) \= source\_token\_account { println!("TokenBalance: {}", source\_account.token\_amount.amount); println!("{:#?}", source\_account); } println!( "\\nDestination Token Account Address: {}", destination\_token\_address ); if let Some(destination\_account) \= destination\_token\_account { println!("Token Balance: {}", destination\_account.token\_amount.amount); println!("{:#?}", destination\_account); } println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{initialize\_mint, mint\_to, transfer\_checked}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Generate a second keypair for the token recipient let recipient \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Airdrop 1 SOL to recipient for rent exemption let recipient\_airdrop\_signature \= client .request\_airdrop(&recipient.pubkey(), 1\_000\_000\_000) .await?; client .confirm\_transaction(&recipient\_airdrop\_signature) .await?; loop { let confirmed \= client .confirm\_transaction(&recipient\_airdrop\_signature) .await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Calculate the associated token account address for fee\_payer let source\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account for fee\_payer let create\_source\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Calculate the associated token account address for recipient let destination\_token\_address \= get\_associated\_token\_address( &recipient.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account for recipient let create\_destination\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &recipient.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimal places) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the source token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &source\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_source\_ata\_instruction,\ \ create\_destination\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Amount of tokens to transfer (0.50 tokens with 2 decimals) let transfer\_amount \= 50; // Create transfer\_checked instruction to send tokens from source to destination let transfer\_instruction \= transfer\_checked( &token\_program\_id(), // program id &source\_token\_address, // source &mint.pubkey(), // mint &destination\_token\_address, // destination &fee\_payer.pubkey(), // owner of source &\[&fee\_payer.pubkey()\], // signers transfer\_amount, // amount 2, // decimals )?; // Create transaction for transferring tokens let transaction \= Transaction::new\_signed\_with\_payer( &\[transfer\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; // Get token account balances to verify the transfer let source\_token\_account \= client.get\_token\_account(&source\_token\_address).await?; let destination\_token\_account \= client.get\_token\_account(&destination\_token\_address).await?; println!("Successfully transferred 0.50 tokens from sender to recipient"); println!("\\nMint Address: {}", mint.pubkey()); println!("{:#?}", mint\_data); println!("\\nSource Token Account Address: {}", source\_token\_address); if let Some(source\_account) \= source\_token\_account { println!("TokenBalance: {}", source\_account.token\_amount.amount); println!("{:#?}", source\_account); } println!( "\\nDestination Token Account Address: {}", destination\_token\_address ); if let Some(destination\_account) \= destination\_token\_account { println!("Token Balance: {}", destination\_account.token\_amount.amount); println!("{:#?}", destination\_account); } println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/transfer-tokens#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import transfer\_checked, TransferCheckedParams from spl.token.instructions import get\_associated\_token\_address from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() owner \= Keypair() receiver \= Keypair() mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") \# Token decimals (usually 9 for most tokens) decimals \= 9 \# Amount to transfer (in smallest unit) amount\_to\_transfer \= 10\_000\_000\_000 \# 10 tokens with 9 decimals async with rpc: \# Get associated token addresses source\_token\_account \= get\_associated\_token\_address( owner\=owner.pubkey(), mint\=mint\_address, token\_program\_id\=TOKEN\_PROGRAM\_ID ) destination\_token\_account \= get\_associated\_token\_address( owner\=receiver.pubkey(), mint\=mint\_address, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Create transfer checked instruction transfer\_instruction \= transfer\_checked( TransferCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, source\=source\_token\_account, mint\=mint\_address, dest\=destination\_token\_account, owner\=owner.pubkey(), amount\=amount\_to\_transfer, decimals\=decimals ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[transfer\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"Mint: {mint\_address}") print(f"Source: {source\_token\_account}") print(f"Destination: {destination\_token\_account}") print(f"Amount: {amount\_to\_transfer}") print(f"Decimals: {decimals}") print(f"Owner: {owner.pubkey()}") print(f"Receiver: {receiver.pubkey()}") print(f"Transfer transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import transfer\_checked, TransferCheckedParams from spl.token.instructions import get\_associated\_token\_address from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() owner \= Keypair() receiver \= Keypair() mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") \# Token decimals (usually 9 for most tokens) decimals \= 9 \# Amount to transfer (in smallest unit) amount\_to\_transfer \= 10\_000\_000\_000 \# 10 tokens with 9 decimals async with rpc: \# Get associated token addresses source\_token\_account \= get\_associated\_token\_address( owner\=owner.pubkey(), mint\=mint\_address, token\_program\_id\=TOKEN\_PROGRAM\_ID ) destination\_token\_account \= get\_associated\_token\_address( owner\=receiver.pubkey(), mint\=mint\_address, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Create transfer checked instruction transfer\_instruction \= transfer\_checked( TransferCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, source\=source\_token\_account, mint\=mint\_address, dest\=destination\_token\_account, owner\=owner.pubkey(), amount\=amount\_to\_transfer, decimals\=decimals ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[transfer\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"Mint: {mint\_address}") print(f"Source: {source\_token\_account}") print(f"Destination: {destination\_token\_account}") print(f"Amount: {amount\_to\_transfer}") print(f"Decimals: {decimals}") print(f"Owner: {owner.pubkey()}") print(f"Receiver: {receiver.pubkey()}") print(f"Transfer transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Mint Tokens](https://solana.com/docs/tokens/basics/mint-tokens) [Next\ \ Approve Delegate](https://solana.com/docs/tokens/basics/approve-delegate) ### Table of Contents [How to Transfer Tokens](https://solana.com/docs/tokens/basics/transfer-tokens#how-to-transfer-tokens) [Typescript](https://solana.com/docs/tokens/basics/transfer-tokens#typescript) [Rust](https://solana.com/docs/tokens/basics/transfer-tokens#rust) [Python](https://solana.com/docs/tokens/basics/transfer-tokens#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/transfer-tokens.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Create a Token Account | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Create a Token Account](https://solana.com/docs/tokens/basics/create-token-account) ===================================================================================== Copy MarkdownOpen [What's a Token Account?](https://solana.com/docs/tokens/basics/create-token-account#whats-a-token-account) ------------------------------------------------------------------------------------------------------------ A token account stores your balance of a specific token. Each token account is associated with exactly one mint and tracks your token balance and additional details. Token Account Type /// Account data. #\[repr(C)\] #\[derive(Clone, Copy, Debug, Default, PartialEq)\] pub struct Account { /// The mint associated with this account pub mint: Pubkey, /// The owner of this account. pub owner: Pubkey, /// The amount of tokens this account holds. pub amount: u64, /// If \`delegate\` is \`Some\` then \`delegated\_amount\` represents /// the amount authorized by the delegate pub delegate: COption, /// The account's state pub state: AccountState, /// If \`is\_native.is\_some\`, this is a native token, and the value logs the /// rent-exempt reserve. An Account is required to be rent-exempt, so /// the value is used by the Processor to ensure that wrapped SOL /// accounts do not drop below this threshold. pub is\_native: COption, /// The amount delegated pub delegated\_amount: u64, /// Optional authority to close the account. pub close\_authority: COption, } Note that in the source code, developers call a Token account an `Account` type. Both the [Token Program](https://github.com/solana-program/token/blob/6d18ff73b1dd30703a30b1ca941cb0f1d18c2b2a/program/src/state.rs#L87-L108) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/state.rs#L102-L123) share the same base implementation for the Token account. To hold tokens, you need a token account for that specific mint. Each token account tracks: 1. **Mint**: The specific token type it holds 2. **Owner**: The authority who can transfer tokens from this account ### [Example: USD Coin (USDC)](https://solana.com/docs/tokens/basics/create-token-account#example-usd-coin-usdc) * Mint address: `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` * Circle's token account: `3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa` * This account holds only USDC tokens * Circle controls token through the token account owner authority: `7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE` You can view the details of this token account on [Solana Explorer](https://explorer.solana.com/address/3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa) . **Understanding "Owner" Terminology** The term "owner" can be used in two different contexts: 1. **Token Account Owner**: The authority who can transfer, burn, or delegate tokens. This is stored in the token account's data. 2. **Program Owner**: The program that owns the account (always the Token Program or Token Extension Program for token accounts). When working with token accounts, "owner" typically refers to the authority that can transfer tokens, not the program that owns the account. [What's an Associated Token Account?](https://solana.com/docs/tokens/basics/create-token-account#whats-an-associated-token-account) ------------------------------------------------------------------------------------------------------------------------------------ An associated token account (ATA) is the default token account for a wallet to hold a specific token. It uses a deterministic address (PDA) created by the [Associated Token Program](https://github.com/solana-program/associated-token-account/tree/main/program) . Only token accounts created by the Associated Token Program are called "associated token accounts." ATAs use deterministic addresses, making it easy to find any wallet's token account for a given mint. See the [derivation implementation here](https://github.com/solana-program/associated-token-account/blob/c78722ee39ebf6741cdfa81dffd52135370a5015/interface/src/address.rs#L56) . Associated Token Account Address Derivation pub fn get\_associated\_token\_address\_and\_bump\_seed\_internal( wallet\_address: &Pubkey, token\_mint\_address: &Pubkey, program\_id: &Pubkey, token\_program\_id: &Pubkey, ) \-> (Pubkey, u8) { Pubkey::find\_program\_address( &\[\ \ &wallet\_address.to\_bytes(), // Owner's public key\ \ &token\_program\_id.to\_bytes(), // Token Program or Token Extension Program\ \ &token\_mint\_address.to\_bytes(), // Token mint address\ \ \], program\_id, // Associated Token Program ID ) } For any wallet and token combination, there's exactly one ATA address. This eliminates the need to track token account addresses manually—you can always derive the correct address. **How the Associated Token Program Works** The Associated Token Program is a helper that: * Creates token accounts at deterministic addresses (PDAs) * Makes Cross-Program Invocations (CPIs) to the Token Program * Doesn't maintain any state itself The resulting token accounts are owned by the Token Program and use the standard `Account` structure. [How to Create a Token Account](https://solana.com/docs/tokens/basics/create-token-account#how-to-create-a-token-account) -------------------------------------------------------------------------------------------------------------------------- Creating a token account requires the [`InitializeAccount`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L63) instruction. See the [implementation here](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/processor.rs#L83) . You need two instructions to create a token account: 1. System Program: Create an account with allocated space for a token account and transfer ownership to the Token Program 2. Token Program: Initialize the token account data ### [Typescript](https://solana.com/docs/tokens/basics/create-token-account#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getInitializeAccount2Instruction, getInitializeMintInstruction, getMintSize, getTokenSize, TOKEN\_PROGRAM\_ADDRESS } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and mint keypair) const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address); console.log("Transaction Signature:", transactionSignature); // Generate keypair to use as address of token account const tokenAccount \= await generateKeyPairSigner(); // Get token account size (in bytes) const tokenAccountSpace \= BigInt(getTokenSize()); // Get minimum balance for rent exemption const tokenAccountRent \= await rpc .getMinimumBalanceForRentExemption(tokenAccountSpace) .send(); // Instruction to create new account for token account (token program) // Invokes the system program const createTokenAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: tokenAccount, lamports: tokenAccountRent, space: tokenAccountSpace, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize token account data // Invokes the token program const initializeTokenAccountInstruction \= getInitializeAccount2Instruction({ account: tokenAccount.address, mint: mint.address, owner: feePayer.address }); const instructions2 \= \[\ \ createTokenAccountInstruction,\ \ initializeTokenAccountInstruction\ \ \]; // Create transaction message for token account creation const tokenAccountMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions2, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and token account keypair) const signedTokenAccountTx \= await signTransactionMessageWithSigners(tokenAccountMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTokenAccountTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedTokenAccountTx); console.log("Token Account Address:", tokenAccount.address); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getInitializeAccount2Instruction, getInitializeMintInstruction, getMintSize, getTokenSize, TOKEN\_PROGRAM\_ADDRESS } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and mint keypair) const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address); console.log("Transaction Signature:", transactionSignature); // Generate keypair to use as address of token account const tokenAccount \= await generateKeyPairSigner(); // Get token account size (in bytes) const tokenAccountSpace \= BigInt(getTokenSize()); // Get minimum balance for rent exemption const tokenAccountRent \= await rpc .getMinimumBalanceForRentExemption(tokenAccountSpace) .send(); // Instruction to create new account for token account (token program) // Invokes the system program const createTokenAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: tokenAccount, lamports: tokenAccountRent, space: tokenAccountSpace, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize token account data // Invokes the token program const initializeTokenAccountInstruction \= getInitializeAccount2Instruction({ account: tokenAccount.address, mint: mint.address, owner: feePayer.address }); const instructions2 \= \[\ \ createTokenAccountInstruction,\ \ initializeTokenAccountInstruction\ \ \]; // Create transaction message for token account creation const tokenAccountMessage \= pipe( createTransactionMessage({ version: 0 }), // Create transaction message (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash (tx) \=> appendTransactionMessageInstructions(instructions2, tx) // Append instructions ); // Sign transaction message with required signers (fee payer and token account keypair) const signedTokenAccountTx \= await signTransactionMessageWithSigners(tokenAccountMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTokenAccountTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedTokenAccountTx); console.log("Token Account Address:", tokenAccount.address); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/create-token-account#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_token\_interface::{ id as token\_program\_id, instruction::{initialize\_account, initialize\_mint}, state::{Account, Mint}, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_account\_instruction, initialize\_mint\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; println!("Mint Address: {}", &mint.pubkey()); println!("{:#?}", mint\_data); println!("Transaction Signature: {}", transaction\_signature); // Generate keypair to use as address of token account let token\_account \= Keypair::new(); // Get token account size (in bytes) let token\_account\_space \= Account::LEN; let token\_account\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(token\_account\_space) .await?; // Instruction to create new account for token account (token program) let create\_token\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &token\_account.pubkey(), // new account (token account) token\_account\_rent, // lamports token\_account\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize token account data let initialize\_token\_account\_instruction \= initialize\_account( &token\_program\_id(), &token\_account.pubkey(), // account &mint.pubkey(), // mint &fee\_payer.pubkey(), // owner )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_token\_account\_instruction,\ \ initialize\_token\_account\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &token\_account\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_account(&token\_account.pubkey()).await?; let token\_data \= Account::unpack(&token.data)?; println!("\\nToken Account Address: {}", &token\_account.pubkey()); println!("{:#?}", token\_data); println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_token\_interface::{ id as token\_program\_id, instruction::{initialize\_account, initialize\_mint}, state::{Account, Mint}, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_account\_instruction, initialize\_mint\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; println!("Mint Address: {}", &mint.pubkey()); println!("{:#?}", mint\_data); println!("Transaction Signature: {}", transaction\_signature); // Generate keypair to use as address of token account let token\_account \= Keypair::new(); // Get token account size (in bytes) let token\_account\_space \= Account::LEN; let token\_account\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(token\_account\_space) .await?; // Instruction to create new account for token account (token program) let create\_token\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &token\_account.pubkey(), // new account (token account) token\_account\_rent, // lamports token\_account\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize token account data let initialize\_token\_account\_instruction \= initialize\_account( &token\_program\_id(), &token\_account.pubkey(), // account &mint.pubkey(), // mint &fee\_payer.pubkey(), // owner )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_token\_account\_instruction,\ \ initialize\_token\_account\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &token\_account\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_account(&token\_account.pubkey()).await?; let token\_data \= Account::unpack(&token.data)?; println!("\\nToken Account Address: {}", &token\_account.pubkey()); println!("{:#?}", token\_data); println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. [How to Create an Associated Token Account](https://solana.com/docs/tokens/basics/create-token-account#how-to-create-an-associated-token-account) -------------------------------------------------------------------------------------------------------------------------------------------------- Creating an Associated Token Account (ATA) requires the [`Create`](https://github.com/solana-program/associated-token-account/blob/c78722ee39ebf6741cdfa81dffd52135370a5015/program/src/instruction.rs#L18) instruction. See the [implementation here](https://github.com/solana-program/associated-token-account/blob/c78722ee39ebf6741cdfa81dffd52135370a5015/program/src/processor.rs#L66) . This single instruction automatically handles creating the token account and initializing it through Cross Program Invocations (CPI). ### [Typescript](https://solana.com/docs/tokens/basics/create-token-account#typescript-1) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log("Transaction Signature:", transactionSignature); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); // Get a fresh blockhash for the second transaction const { value: latestBlockhash2 } \= await rpc.getLatestBlockhash().send(); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create transaction message const transactionMessage2 \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash2, tx), (tx) \=> appendTransactionMessageInstructions(\[createAtaInstruction\], tx) ); // Sign transaction message with all required signers const signedTransaction2 \= await signTransactionMessageWithSigners(transactionMessage2); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction2, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedTransaction2); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 2, mintAuthority: feePayer.address }); const instructions \= \[createAccountInstruction, initializeMintInstruction\]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log("Transaction Signature:", transactionSignature); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); // Get a fresh blockhash for the second transaction const { value: latestBlockhash2 } \= await rpc.getLatestBlockhash().send(); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create transaction message const transactionMessage2 \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash2, tx), (tx) \=> appendTransactionMessageInstructions(\[createAtaInstruction\], tx) ); // Sign transaction message with all required signers const signedTransaction2 \= await signTransactionMessageWithSigners(transactionMessage2); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction2, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedTransaction2); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/create-token-account#rust-1) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::initialize\_mint, state::{Account, Mint}, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_account\_instruction, initialize\_mint\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; println!("Mint Address: {}", mint.pubkey()); println!("{:#?}", mint\_data); println!("Transaction Signature: {}", transaction\_signature); // Derive the associated token account address for fee\_payer let associated\_token\_account \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address (owner) &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Create transaction for associated token account creation let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_ata\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_account(&associated\_token\_account).await?; let token\_data \= Account::unpack(&token.data)?; println!( "\\nAssociated Token Account Address: {}", associated\_token\_account ); println!("{:#?}", token\_data); println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::initialize\_mint, state::{Account, Mint}, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority 2, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_account\_instruction, initialize\_mint\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; println!("Mint Address: {}", mint.pubkey()); println!("{:#?}", mint\_data); println!("Transaction Signature: {}", transaction\_signature); // Derive the associated token account address for fee\_payer let associated\_token\_account \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address (owner) &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Create transaction for associated token account creation let transaction \= Transaction::new\_signed\_with\_payer( &\[create\_ata\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_account(&associated\_token\_account).await?; let token\_data \= Account::unpack(&token.data)?; println!( "\\nAssociated Token Account Address: {}", associated\_token\_account ); println!("{:#?}", token\_data); println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/create-token-account#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import create\_associated\_token\_account, get\_associated\_token\_address from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") payer \= Keypair() owner \= Keypair() \# Example mint address (USDC on devnet) mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") \# Get associated token account address associated\_token\_account \= get\_associated\_token\_address(owner.pubkey(), mint\_address) async with rpc: \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create associated token account instruction create\_token\_account\_instruction \= create\_associated\_token\_account( payer\=payer.pubkey(), owner\=owner.pubkey(), mint\=mint\_address, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[create\_token\_account\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer\]) print(f"Payer: {payer.pubkey()}") print(f"Owner: {owner.pubkey()}") print(f"Associated Token Account: {associated\_token\_account}") print(f"Mint: {mint\_address}") print(f"Associated token account created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import create\_associated\_token\_account, get\_associated\_token\_address from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") payer \= Keypair() owner \= Keypair() \# Example mint address (USDC on devnet) mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") \# Get associated token account address associated\_token\_account \= get\_associated\_token\_address(owner.pubkey(), mint\_address) async with rpc: \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create associated token account instruction create\_token\_account\_instruction \= create\_associated\_token\_account( payer\=payer.pubkey(), owner\=owner.pubkey(), mint\=mint\_address, token\_program\_id\=TOKEN\_PROGRAM\_ID ) \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[create\_token\_account\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer\]) print(f"Payer: {payer.pubkey()}") print(f"Owner: {owner.pubkey()}") print(f"Associated Token Account: {associated\_token\_account}") print(f"Mint: {mint\_address}") print(f"Associated token account created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Create a Token Mint](https://solana.com/docs/tokens/basics/create-mint) [Next\ \ Mint Tokens](https://solana.com/docs/tokens/basics/mint-tokens) ### Table of Contents [What's a Token Account?](https://solana.com/docs/tokens/basics/create-token-account#whats-a-token-account) [Example: USD Coin (USDC)](https://solana.com/docs/tokens/basics/create-token-account#example-usd-coin-usdc) [What's an Associated Token Account?](https://solana.com/docs/tokens/basics/create-token-account#whats-an-associated-token-account) [How to Create a Token Account](https://solana.com/docs/tokens/basics/create-token-account#how-to-create-a-token-account) [Typescript](https://solana.com/docs/tokens/basics/create-token-account#typescript) [Rust](https://solana.com/docs/tokens/basics/create-token-account#rust) [How to Create an Associated Token Account](https://solana.com/docs/tokens/basics/create-token-account#how-to-create-an-associated-token-account) [Typescript](https://solana.com/docs/tokens/basics/create-token-account#typescript-1) [Rust](https://solana.com/docs/tokens/basics/create-token-account#rust-1) [Python](https://solana.com/docs/tokens/basics/create-token-account#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/create-token-account.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Revoke Delegate | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Revoke Delegate](https://solana.com/docs/tokens/basics/revoke-delegate) ========================================================================= Copy MarkdownOpen [How to Revoke delegate](https://solana.com/docs/tokens/basics/revoke-delegate#how-to-revoke-delegate) ------------------------------------------------------------------------------------------------------- The [`Revoke`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/interface/src/instruction.rs#L133C5-L133C11) instruction removes all transfer permissions from the currently approved delegate. After revocation, the delegate can no longer transfer any tokens from your account. For the Token Program, only the token account owner can revoke a delegate. For the Token Extension Program, the token account owner and current delegate can revoke the delegation. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L140) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L182) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/revoke-delegate#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getApproveCheckedInstruction, getRevokeInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer and delegate const feePayer \= await generateKeyPairSigner(); const delegate \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); // Create instruction to approve delegate const approveInstruction \= getApproveCheckedInstruction({ source: associatedTokenAddress, mint: mint.address, delegate: delegate.address, owner: feePayer, amount: 1\_000\_000\_000n, // 1.0 tokens with 9 decimals decimals: 9 }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction,\ \ approveInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("\\nMint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("\\nDelegate Address:", delegate.address.toString()); console.log("Successfully approved delegate to transfer 1.0 tokens"); console.log("Transaction Signature:", transactionSignature); // Get a fresh blockhash for the revoke transaction const { value: revokeBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to revoke delegate const revokeInstruction \= getRevokeInstruction({ source: associatedTokenAddress, owner: feePayer }); // Create transaction message for revoke const revokeTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(revokeBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[revokeInstruction\], tx) ); // Sign transaction message with all required signers const signedRevokeTx \= await signTransactionMessageWithSigners(revokeTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedRevokeTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedRevokeTx); console.log("\\nSuccessfully revoked delegation from the token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getApproveCheckedInstruction, getRevokeInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer and delegate const feePayer \= await generateKeyPairSigner(); const delegate \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); // Create instruction to approve delegate const approveInstruction \= getApproveCheckedInstruction({ source: associatedTokenAddress, mint: mint.address, delegate: delegate.address, owner: feePayer, amount: 1\_000\_000\_000n, // 1.0 tokens with 9 decimals decimals: 9 }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction,\ \ approveInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("\\nMint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("\\nDelegate Address:", delegate.address.toString()); console.log("Successfully approved delegate to transfer 1.0 tokens"); console.log("Transaction Signature:", transactionSignature); // Get a fresh blockhash for the revoke transaction const { value: revokeBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to revoke delegate const revokeInstruction \= getRevokeInstruction({ source: associatedTokenAddress, owner: feePayer }); // Create transaction message for revoke const revokeTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(revokeBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[revokeInstruction\], tx) ); // Sign transaction message with all required signers const signedRevokeTx \= await signTransactionMessageWithSigners(revokeTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedRevokeTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedRevokeTx); console.log("\\nSuccessfully revoked delegation from the token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/revoke-delegate#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{approve\_checked, initialize\_mint, mint\_to, revoke}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Generate a keypair for the delegate let delegate \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (1000 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Amount of tokens to approve (1 token with 2 decimals) let approve\_amount \= 1\_00; // Create approve\_checked instruction let approve\_instruction \= approve\_checked( &token\_program\_id(), // program id &associated\_token\_address, // source token account &mint.pubkey(), // mint &delegate.pubkey(), // delegate &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers approve\_amount, // amount decimals, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ approve\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_token\_account(&associated\_token\_address).await?; println!("Token Account Address: {}", associated\_token\_address); println!("\\nToken Account Delegate Approved"); if let Some(token) \= token { println!("{:#?}", token); } // Create revoke instruction let revoke\_instruction \= revoke( &token\_program\_id(), // program id &associated\_token\_address, // source token account &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction for revoking delegation let transaction \= Transaction::new\_signed\_with\_payer( &\[revoke\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_token\_account(&associated\_token\_address).await?; println!("\\nToken Account Delegate Revoked"); if let Some(token) \= token { println!("{:#?}", token); } println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{approve\_checked, initialize\_mint, mint\_to, revoke}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Generate a keypair for the delegate let delegate \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (1000 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Amount of tokens to approve (1 token with 2 decimals) let approve\_amount \= 1\_00; // Create approve\_checked instruction let approve\_instruction \= approve\_checked( &token\_program\_id(), // program id &associated\_token\_address, // source token account &mint.pubkey(), // mint &delegate.pubkey(), // delegate &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers approve\_amount, // amount decimals, // decimals )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ approve\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_token\_account(&associated\_token\_address).await?; println!("Token Account Address: {}", associated\_token\_address); println!("\\nToken Account Delegate Approved"); if let Some(token) \= token { println!("{:#?}", token); } // Create revoke instruction let revoke\_instruction \= revoke( &token\_program\_id(), // program id &associated\_token\_address, // source token account &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction for revoking delegation let transaction \= Transaction::new\_signed\_with\_payer( &\[revoke\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_token\_account(&associated\_token\_address).await?; println!("\\nToken Account Delegate Revoked"); if let Some(token) \= token { println!("{:#?}", token); } println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/revoke-delegate#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import create\_account, CreateAccountParams from spl.token.instructions import ( initialize\_mint, InitializeMintParams, create\_associated\_token\_account, mint\_to\_checked, MintToCheckedParams, revoke, RevokeParams, get\_associated\_token\_address ) from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID \# Constants DECIMALS \= 9 async def setup(rpc, mint\_authority, latest\_blockhash): """ The setup function initializes the mint and associated token accounts, and mints tokens to said associated token account """ mint \= Keypair() space \= 82 \# getMintSize() equivalent for SPL Token \# Get minimum balance for rent exemption rent \= await rpc.get\_minimum\_balance\_for\_rent\_exemption(space) \# Create & initialize mint account create\_account\_instruction \= create\_account( CreateAccountParams( from\_pubkey\=mint\_authority.pubkey(), to\_pubkey\=mint.pubkey(), lamports\=rent.value, space\=space, owner\=TOKEN\_PROGRAM\_ID ) ) initialize\_mint\_instruction \= initialize\_mint( InitializeMintParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), decimals\=DECIMALS, mint\_authority\=mint\_authority.pubkey(), freeze\_authority\=None ) ) \# Create associated token account authority\_ata \= get\_associated\_token\_address( owner\=mint\_authority.pubkey(), mint\=mint.pubkey(), token\_program\_id\=TOKEN\_PROGRAM\_ID ) create\_authority\_ata\_instruction \= create\_associated\_token\_account( payer\=mint\_authority.pubkey(), owner\=mint\_authority.pubkey(), mint\=mint.pubkey() ) \# Mint to token account mint\_to\_instruction \= mint\_to\_checked( MintToCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), dest\=authority\_ata, mint\_authority\=mint\_authority.pubkey(), amount\=1\_000\_000\_000\_000, \# 1000 tokens decimals\=DECIMALS ) ) instructions \= \[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_authority\_ata\_instruction,\ \ mint\_to\_instruction\ \ \] \# Create transaction message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority, mint\]) print("Setup transaction created successfully") print(f"Mint: {mint.pubkey()}") print(f"Authority ATA: {authority\_ata}") return { "mint": mint.pubkey(), "authority\_ata": authority\_ata } async def main(): rpc \= AsyncClient("http://localhost:8899") \# Constants mint\_authority \= Keypair() async with rpc: \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Setup mint and associated token accounts setup\_result \= await setup(rpc, mint\_authority, latest\_blockhash) authority\_ata \= setup\_result\["authority\_ata"\] \# Create revoke delegate instruction revoke\_delegate\_ix \= revoke( RevokeParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=authority\_ata, owner\=mint\_authority.pubkey() ) ) \# Create transaction message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=\[revoke\_delegate\_ix\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority\]) print(f"\\nRevoke Delegate Transaction:") print(f"Source: {authority\_ata}") print(f"Owner: {mint\_authority.pubkey()}") print(f"Revoke delegate transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import create\_account, CreateAccountParams from spl.token.instructions import ( initialize\_mint, InitializeMintParams, create\_associated\_token\_account, mint\_to\_checked, MintToCheckedParams, revoke, RevokeParams, get\_associated\_token\_address ) from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID \# Constants DECIMALS \= 9 async def setup(rpc, mint\_authority, latest\_blockhash): """ The setup function initializes the mint and associated token accounts, and mints tokens to said associated token account """ mint \= Keypair() space \= 82 \# getMintSize() equivalent for SPL Token \# Get minimum balance for rent exemption rent \= await rpc.get\_minimum\_balance\_for\_rent\_exemption(space) \# Create & initialize mint account create\_account\_instruction \= create\_account( CreateAccountParams( from\_pubkey\=mint\_authority.pubkey(), to\_pubkey\=mint.pubkey(), lamports\=rent.value, space\=space, owner\=TOKEN\_PROGRAM\_ID ) ) initialize\_mint\_instruction \= initialize\_mint( InitializeMintParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), decimals\=DECIMALS, mint\_authority\=mint\_authority.pubkey(), freeze\_authority\=None ) ) \# Create associated token account authority\_ata \= get\_associated\_token\_address( owner\=mint\_authority.pubkey(), mint\=mint.pubkey(), token\_program\_id\=TOKEN\_PROGRAM\_ID ) create\_authority\_ata\_instruction \= create\_associated\_token\_account( payer\=mint\_authority.pubkey(), owner\=mint\_authority.pubkey(), mint\=mint.pubkey() ) \# Mint to token account mint\_to\_instruction \= mint\_to\_checked( MintToCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), dest\=authority\_ata, mint\_authority\=mint\_authority.pubkey(), amount\=1\_000\_000\_000\_000, \# 1000 tokens decimals\=DECIMALS ) ) instructions \= \[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_authority\_ata\_instruction,\ \ mint\_to\_instruction\ \ \] \# Create transaction message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority, mint\]) print("Setup transaction created successfully") print(f"Mint: {mint.pubkey()}") print(f"Authority ATA: {authority\_ata}") return { "mint": mint.pubkey(), "authority\_ata": authority\_ata } async def main(): rpc \= AsyncClient("http://localhost:8899") \# Constants mint\_authority \= Keypair() async with rpc: \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Setup mint and associated token accounts setup\_result \= await setup(rpc, mint\_authority, latest\_blockhash) authority\_ata \= setup\_result\["authority\_ata"\] \# Create revoke delegate instruction revoke\_delegate\_ix \= revoke( RevokeParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=authority\_ata, owner\=mint\_authority.pubkey() ) ) \# Create transaction message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=\[revoke\_delegate\_ix\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority\]) print(f"\\nRevoke Delegate Transaction:") print(f"Source: {authority\_ata}") print(f"Owner: {mint\_authority.pubkey()}") print(f"Revoke delegate transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Approve Delegate](https://solana.com/docs/tokens/basics/approve-delegate) [Next\ \ Set Authority](https://solana.com/docs/tokens/basics/set-authority) ### Table of Contents [How to Revoke delegate](https://solana.com/docs/tokens/basics/revoke-delegate#how-to-revoke-delegate) [Typescript](https://solana.com/docs/tokens/basics/revoke-delegate#typescript) [Rust](https://solana.com/docs/tokens/basics/revoke-delegate#rust) [Python](https://solana.com/docs/tokens/basics/revoke-delegate#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/revoke-delegate.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter Revoke Delegate | Solana --- # Thaw Account | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Thaw Account](https://solana.com/docs/tokens/basics/thaw-account) =================================================================== Copy MarkdownOpen [Thaw Account](https://solana.com/docs/tokens/basics/thaw-account#thaw-account) -------------------------------------------------------------------------------- The [`ThawAccount`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L243) instruction reverses a freeze, restoring full functionality to a previously frozen token account. After thawing, the account can once again send and receive tokens normally. Only the freeze authority of the token's mint can thaw accounts. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L243) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L306) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/thaw-account#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getFreezeAccountInstruction, getThawAccountInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address, freezeAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); // Create instruction to freeze the token account const freezeInstruction \= getFreezeAccountInstruction({ account: associatedTokenAddress, mint: mint.address, owner: feePayer.address }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction,\ \ freezeInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1000.0 tokens and frozen the account"); // Get a fresh blockhash for the thaw transaction const { value: thawBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to thaw the frozen token account const thawInstruction \= getThawAccountInstruction({ account: associatedTokenAddress, mint: mint.address, owner: feePayer.address }); // Create transaction message for thawing const thawTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(thawBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[thawInstruction\], tx) ); // Sign transaction message with all required signers const signedThawTx \= await signTransactionMessageWithSigners(thawTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedThawTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedThawTx); console.log("Successfully thawed the frozen token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getFreezeAccountInstruction, getThawAccountInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address, freezeAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); // Create instruction to freeze the token account const freezeInstruction \= getFreezeAccountInstruction({ account: associatedTokenAddress, mint: mint.address, owner: feePayer.address }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction,\ \ freezeInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1000.0 tokens and frozen the account"); // Get a fresh blockhash for the thaw transaction const { value: thawBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to thaw the frozen token account const thawInstruction \= getThawAccountInstruction({ account: associatedTokenAddress, mint: mint.address, owner: feePayer.address }); // Create transaction message for thawing const thawTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(thawBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[thawInstruction\], tx) ); // Sign transaction message with all required signers const signedThawTx \= await signTransactionMessageWithSigners(thawTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedThawTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedThawTx); console.log("Successfully thawed the frozen token account"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/thaw-account#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{freeze\_account, initialize\_mint, mint\_to, thaw\_account}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Get the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create freeze account instruction let freeze\_instruction \= freeze\_account( &token\_program\_id(), // program id &associated\_token\_address, // token account to freeze &mint.pubkey(), // mint &fee\_payer.pubkey(), // freeze authority &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ freeze\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; println!("Token Account Address: {}", associated\_token\_address); if let Some(token\_account) \= token\_account { println!("\\nToken Account Frozen: {:#?}", token\_account.state); println!("{:#?}", token\_account); } // Create thaw account instruction let thaw\_instruction \= thaw\_account( &token\_program\_id(), // program id &associated\_token\_address, // token account to thaw &mint.pubkey(), // mint &fee\_payer.pubkey(), // freeze authority &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction for thawing token account let transaction \= Transaction::new\_signed\_with\_payer( &\[thaw\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!( "\\nToken Account Thawed (Unfrozen): {:#?}", token\_account.state ); println!("{:#?}", token\_account); } Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{freeze\_account, initialize\_mint, mint\_to, thaw\_account}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Get the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create freeze account instruction let freeze\_instruction \= freeze\_account( &token\_program\_id(), // program id &associated\_token\_address, // token account to freeze &mint.pubkey(), // mint &fee\_payer.pubkey(), // freeze authority &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ freeze\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; println!("Token Account Address: {}", associated\_token\_address); if let Some(token\_account) \= token\_account { println!("\\nToken Account Frozen: {:#?}", token\_account.state); println!("{:#?}", token\_account); } // Create thaw account instruction let thaw\_instruction \= thaw\_account( &token\_program\_id(), // program id &associated\_token\_address, // token account to thaw &mint.pubkey(), // mint &fee\_payer.pubkey(), // freeze authority &\[&fee\_payer.pubkey()\], // signers )?; // Create transaction for thawing token account let transaction \= Transaction::new\_signed\_with\_payer( &\[thaw\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!( "\\nToken Account Thawed (Unfrozen): {:#?}", token\_account.state ); println!("{:#?}", token\_account); } Ok(()) } Console RunClick to execute the code. Is this page helpful? [Previous\ \ Freeze Account](https://solana.com/docs/tokens/basics/freeze-account) [Next\ \ Extensions](https://solana.com/docs/tokens/extensions) ### Table of Contents [Thaw Account](https://solana.com/docs/tokens/basics/thaw-account#thaw-account) [Typescript](https://solana.com/docs/tokens/basics/thaw-account#typescript) [Rust](https://solana.com/docs/tokens/basics/thaw-account#rust) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/thaw-account.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Burn Tokens | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Burn Tokens](https://solana.com/docs/tokens/basics/burn-tokens) ================================================================= Copy MarkdownOpen [Burn Tokens](https://solana.com/docs/tokens/basics/burn-tokens#burn-tokens) ----------------------------------------------------------------------------- The [`BurnChecked`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/interface/src/instruction.rs#L359C5-L359C16) instruction permanently destroys tokens by reducing the balance in a token account. Burned tokens are removed from circulation and decreases the `supply` tracked on the mint account. Only the token account owner can burn tokens from their account. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/interface/src/instruction.rs#L359C5-L359C16) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L413) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/burn-tokens#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getBurnCheckedInstruction, fetchToken } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1000.0 tokens"); // Fetch token account to check balance before burn const tokenAccountBefore \= await fetchToken(rpc, associatedTokenAddress); console.log( "\\nToken balance before burn:", tokenAccountBefore.data.amount / 10n \*\* 9n, "tokens" ); // Get a fresh blockhash for the burn transaction const { value: burnBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to burn tokens const burnInstruction \= getBurnCheckedInstruction({ account: associatedTokenAddress, mint: mint.address, authority: feePayer.address, amount: 10\_000\_000\_000n, // 10.0 tokens with 9 decimals decimals: 9 }); // Create transaction message for burning const burnTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(burnBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[burnInstruction\], tx) ); // Sign transaction message with all required signers const signedBurnTx \= await signTransactionMessageWithSigners(burnTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedBurnTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedBurnTx); // Fetch token account to check balance after burn const tokenAccountAfter \= await fetchToken(rpc, associatedTokenAddress); console.log( "Token balance after burn:", tokenAccountAfter.data.amount / 10n \*\* 9n, "tokens" ); console.log("\\nSuccessfully burned 10.0 tokens"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getBurnCheckedInstruction, fetchToken } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer const feePayer \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); console.log("Successfully minted 1000.0 tokens"); // Fetch token account to check balance before burn const tokenAccountBefore \= await fetchToken(rpc, associatedTokenAddress); console.log( "\\nToken balance before burn:", tokenAccountBefore.data.amount / 10n \*\* 9n, "tokens" ); // Get a fresh blockhash for the burn transaction const { value: burnBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to burn tokens const burnInstruction \= getBurnCheckedInstruction({ account: associatedTokenAddress, mint: mint.address, authority: feePayer.address, amount: 10\_000\_000\_000n, // 10.0 tokens with 9 decimals decimals: 9 }); // Create transaction message for burning const burnTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(burnBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[burnInstruction\], tx) ); // Sign transaction message with all required signers const signedBurnTx \= await signTransactionMessageWithSigners(burnTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedBurnTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedBurnTx); // Fetch token account to check balance after burn const tokenAccountAfter \= await fetchToken(rpc, associatedTokenAddress); console.log( "Token balance after burn:", tokenAccountAfter.data.amount / 10n \*\* 9n, "tokens" ); console.log("\\nSuccessfully burned 10.0 tokens"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/burn-tokens#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{burn\_checked, initialize\_mint, mint\_to}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Fetch token account to check balance before burn let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!( "Token balance before burn: {} tokens", token\_account.token\_amount.ui\_amount\_string ); println!("{:#?}", token\_account); } let burn\_amount \= 30\_00; // Create burn\_checked instruction let burn\_instruction \= burn\_checked( &token\_program\_id(), // program id &associated\_token\_address, // token account &mint.pubkey(), // mint &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers burn\_amount, // amount decimals, // decimals )?; // Create transaction for burning tokens let transaction \= Transaction::new\_signed\_with\_payer( &\[burn\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!( "\\nToken balance after burn: {} tokens", token\_account.token\_amount.ui\_amount\_string ); println!("{:#?}", token\_account); } println!("\\nMint Supply reduced after burn"); let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; println!("{:#?}", mint\_data); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{burn\_checked, initialize\_mint, mint\_to}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Fetch token account to check balance before burn let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!( "Token balance before burn: {} tokens", token\_account.token\_amount.ui\_amount\_string ); println!("{:#?}", token\_account); } let burn\_amount \= 30\_00; // Create burn\_checked instruction let burn\_instruction \= burn\_checked( &token\_program\_id(), // program id &associated\_token\_address, // token account &mint.pubkey(), // mint &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers burn\_amount, // amount decimals, // decimals )?; // Create transaction for burning tokens let transaction \= Transaction::new\_signed\_with\_payer( &\[burn\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; let token\_account \= client.get\_token\_account(&associated\_token\_address).await?; if let Some(token\_account) \= token\_account { println!( "\\nToken balance after burn: {} tokens", token\_account.token\_amount.ui\_amount\_string ); println!("{:#?}", token\_account); } println!("\\nMint Supply reduced after burn"); let mint\_account \= client.get\_account(&mint.pubkey()).await?; let mint\_data \= Mint::unpack(&mint\_account.data)?; println!("{:#?}", mint\_data); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/burn-tokens#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import burn, BurnParams from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() owner \= Keypair() mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") token\_account \= Pubkey.from\_string("GfVPzUxMDvhFJ1Xs6C9i47XQRSapTd8LHw5grGuTquyQ") \# Amount to burn (in smallest unit) amount\_to\_burn \= 500000000 \# 0.5 tokens with 9 decimals async with rpc: \# Create burn instruction burn\_instruction \= burn( BurnParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=token\_account, mint\=mint\_address, owner\=owner.pubkey(), amount\=amount\_to\_burn ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[burn\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"Mint: {mint\_address}") print(f"Token Account: {token\_account}") print(f"Amount to burn: {amount\_to\_burn}") print(f"Owner: {owner.pubkey()}") print(f"Payer: {payer.pubkey()}") print(f"Burn transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.pubkey import Pubkey from solders.transaction import VersionedTransaction from solders.message import MessageV0 from spl.token.instructions import burn, BurnParams from spl.token.constants import TOKEN\_PROGRAM\_ID async def main(): rpc \= AsyncClient("http://localhost:8899") \# Example keypairs and addresses payer \= Keypair() owner \= Keypair() mint\_address \= Pubkey.from\_string("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU") token\_account \= Pubkey.from\_string("GfVPzUxMDvhFJ1Xs6C9i47XQRSapTd8LHw5grGuTquyQ") \# Amount to burn (in smallest unit) amount\_to\_burn \= 500000000 \# 0.5 tokens with 9 decimals async with rpc: \# Create burn instruction burn\_instruction \= burn( BurnParams( program\_id\=TOKEN\_PROGRAM\_ID, account\=token\_account, mint\=mint\_address, owner\=owner.pubkey(), amount\=amount\_to\_burn ) ) \# Get latest blockhash recent\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message message \= MessageV0.try\_compile( payer\=payer.pubkey(), instructions\=\[burn\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=recent\_blockhash.value.blockhash ) \# Create transaction transaction \= VersionedTransaction(message, \[payer, owner\]) print(f"Mint: {mint\_address}") print(f"Token Account: {token\_account}") print(f"Amount to burn: {amount\_to\_burn}") print(f"Owner: {owner.pubkey()}") print(f"Payer: {payer.pubkey()}") print(f"Burn transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Set Authority](https://solana.com/docs/tokens/basics/set-authority) [Next\ \ Sync Native](https://solana.com/docs/tokens/basics/sync-native) ### Table of Contents [Burn Tokens](https://solana.com/docs/tokens/basics/burn-tokens#burn-tokens) [Typescript](https://solana.com/docs/tokens/basics/burn-tokens#typescript) [Rust](https://solana.com/docs/tokens/basics/burn-tokens#rust) [Python](https://solana.com/docs/tokens/basics/burn-tokens#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/burn-tokens.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter --- # Approve Delegate | Solana [Solana Documentation](https://solana.com/docs) [Tokens on Solana](https://solana.com/docs/tokens) [Basics](https://solana.com/docs/tokens/basics) [Approve Delegate](https://solana.com/docs/tokens/basics/approve-delegate) =========================================================================== Copy MarkdownOpen [How to Approve delegate](https://solana.com/docs/tokens/basics/approve-delegate#how-to-approve-delegate) ---------------------------------------------------------------------------------------------------------- The [`ApproveChecked`](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L295) instruction grants another account (the delegate) permission to transfer a specific amount of tokens from your token account. The delegate can transfer tokens up to the approved amount, but cannot exceed it. Only the token account owner can approve a delegate, and each token account can have only one delegate at a time. Any new approval overwrites the previous one. The [Token Program](https://github.com/solana-program/token/blob/a7c488ca39ed4cd71a87950ed854929816e9099f/program/src/instruction.rs#L295) and [Token Extension Program](https://github.com/solana-program/token-2022/blob/efd0c957fefbd79882d77df5fb2dac88c001249c/program/src/instruction.rs#L361) share similar implementations to achieve the same functionality. ### [Typescript](https://solana.com/docs/tokens/basics/approve-delegate#typescript) Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getApproveCheckedInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer and delegate const feePayer \= await generateKeyPairSigner(); const delegate \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); // Get a fresh blockhash for the approve transaction const { value: approveBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to approve delegate const approveInstruction \= getApproveCheckedInstruction({ source: associatedTokenAddress, mint: mint.address, delegate: delegate.address, owner: feePayer, amount: 1\_000\_000\_000n, // 1.0 tokens with 9 decimals decimals: 9 }); // Create transaction message for approval const approveTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(approveBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[approveInstruction\], tx) ); // Sign transaction message with all required signers const signedApproveTx \= await signTransactionMessageWithSigners(approveTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedApproveTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedApproveTx); console.log("\\nDelegate Address:", delegate.address.toString()); console.log("Successfully approved delegate to transfer 1.0 tokens"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. Kit Legacy Legacy Helper import { airdropFactory, appendTransactionMessageInstructions, createSolanaRpc, createSolanaRpcSubscriptions, createTransactionMessage, generateKeyPairSigner, getSignatureFromTransaction, lamports, pipe, sendAndConfirmTransactionFactory, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners } from "@solana/kit"; import { getCreateAccountInstruction } from "@solana-program/system"; import { getCreateAssociatedTokenInstructionAsync, getInitializeMintInstruction, getMintSize, TOKEN\_PROGRAM\_ADDRESS, findAssociatedTokenPda, getMintToInstruction, getApproveCheckedInstruction } from "@solana-program/token"; // Create Connection, local validator in this example const rpc \= createSolanaRpc("http://localhost:8899"); const rpcSubscriptions \= createSolanaRpcSubscriptions("ws://localhost:8900"); // Generate keypairs for fee payer and delegate const feePayer \= await generateKeyPairSigner(); const delegate \= await generateKeyPairSigner(); // Fund fee payer await airdropFactory({ rpc, rpcSubscriptions })({ recipientAddress: feePayer.address, lamports: lamports(1\_000\_000\_000n), commitment: "confirmed" }); // Generate keypair to use as address of mint const mint \= await generateKeyPairSigner(); // Get default mint account size (in bytes), no extensions enabled const space \= BigInt(getMintSize()); // Get minimum balance for rent exemption const rent \= await rpc.getMinimumBalanceForRentExemption(space).send(); // Get latest blockhash to include in transaction const { value: latestBlockhash } \= await rpc.getLatestBlockhash().send(); // Instruction to create new account for mint (token program) // Invokes the system program const createAccountInstruction \= getCreateAccountInstruction({ payer: feePayer, newAccount: mint, lamports: rent, space, programAddress: TOKEN\_PROGRAM\_ADDRESS }); // Instruction to initialize mint account data // Invokes the token program const initializeMintInstruction \= getInitializeMintInstruction({ mint: mint.address, decimals: 9, mintAuthority: feePayer.address }); // Use findAssociatedTokenPda to derive the ATA address const \[associatedTokenAddress\] \= await findAssociatedTokenPda({ mint: mint.address, owner: feePayer.address, tokenProgram: TOKEN\_PROGRAM\_ADDRESS }); // Create instruction to create the associated token account const createAtaInstruction \= await getCreateAssociatedTokenInstructionAsync({ payer: feePayer, mint: mint.address, owner: feePayer.address }); // Create instruction to mint tokens const mintToInstruction \= getMintToInstruction({ mint: mint.address, token: associatedTokenAddress, mintAuthority: feePayer.address, amount: 1000\_000\_000\_000n // 1000.0 tokens with 9 decimals }); const instructions \= \[\ \ createAccountInstruction,\ \ initializeMintInstruction,\ \ createAtaInstruction,\ \ mintToInstruction\ \ \]; // Create transaction message const transactionMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(instructions, tx) ); // Sign transaction message with all required signers const signedTransaction \= await signTransactionMessageWithSigners(transactionMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedTransaction, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature \= getSignatureFromTransaction(signedTransaction); console.log("Mint Address:", mint.address.toString()); console.log( "Associated Token Account Address:", associatedTokenAddress.toString() ); console.log("Transaction Signature:", transactionSignature); // Get a fresh blockhash for the approve transaction const { value: approveBlockhash } \= await rpc.getLatestBlockhash().send(); // Create instruction to approve delegate const approveInstruction \= getApproveCheckedInstruction({ source: associatedTokenAddress, mint: mint.address, delegate: delegate.address, owner: feePayer, amount: 1\_000\_000\_000n, // 1.0 tokens with 9 decimals decimals: 9 }); // Create transaction message for approval const approveTxMessage \= pipe( createTransactionMessage({ version: 0 }), (tx) \=> setTransactionMessageFeePayerSigner(feePayer, tx), (tx) \=> setTransactionMessageLifetimeUsingBlockhash(approveBlockhash, tx), (tx) \=> appendTransactionMessageInstructions(\[approveInstruction\], tx) ); // Sign transaction message with all required signers const signedApproveTx \= await signTransactionMessageWithSigners(approveTxMessage); // Send and confirm transaction await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })( signedApproveTx, { commitment: "confirmed" } ); // Get transaction signature const transactionSignature2 \= getSignatureFromTransaction(signedApproveTx); console.log("\\nDelegate Address:", delegate.address.toString()); console.log("Successfully approved delegate to transfer 1.0 tokens"); console.log("Transaction Signature:", transactionSignature2); Console RunClick to execute the code. ### [Rust](https://solana.com/docs/tokens/basics/approve-delegate#rust) Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{approve\_checked, initialize\_mint, mint\_to}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Generate a keypair for the delegate let delegate \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Amount of tokens to approve (1 token with 2 decimals) let approve\_amount \= 1\_00; // Create approve\_checked instruction let approve\_instruction \= approve\_checked( &token\_program\_id(), // program id &associated\_token\_address, // source token account &mint.pubkey(), // mint &delegate.pubkey(), // delegate &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers approve\_amount, // amount decimals, // decimals )?; // Create transaction for approving delegate let transaction \= Transaction::new\_signed\_with\_payer( &\[approve\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_token\_account(&associated\_token\_address).await?; println!("Successfully approved delegate for 1.0 token"); println!("\\nDelegate Address: {}", delegate.pubkey()); println!("\\nToken Account Address: {}", associated\_token\_address); if let Some(token) \= token { println!("{:#?}", token); } println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. Rust use anyhow::Result; use solana\_client::nonblocking::rpc\_client::RpcClient; use solana\_commitment\_config::CommitmentConfig; use solana\_sdk::{ program\_pack::Pack, signature::{Keypair, Signer}, transaction::Transaction, }; use solana\_system\_interface::instruction::create\_account; use spl\_associated\_token\_account\_interface::{ address::get\_associated\_token\_address, instruction::create\_associated\_token\_account, }; use spl\_token\_interface::{ id as token\_program\_id, instruction::{approve\_checked, initialize\_mint, mint\_to}, state::Mint, }; #\[tokio::main\] async fn main() \-> Result<()> { // Create connection to local validator let client \= RpcClient::new\_with\_commitment( String::from("http://localhost:8899"), CommitmentConfig::confirmed(), ); let latest\_blockhash \= client.get\_latest\_blockhash().await?; // Generate a new keypair for the fee payer let fee\_payer \= Keypair::new(); // Generate a keypair for the delegate let delegate \= Keypair::new(); // Airdrop 1 SOL to fee payer let airdrop\_signature \= client .request\_airdrop(&fee\_payer.pubkey(), 1\_000\_000\_000) .await?; client.confirm\_transaction(&airdrop\_signature).await?; loop { let confirmed \= client.confirm\_transaction(&airdrop\_signature).await?; if confirmed { break; } } // Generate keypair to use as address of mint let mint \= Keypair::new(); // Number of decimals for the mint let decimals \= 2; // Get default mint account size (in bytes), no extensions enabled let mint\_space \= Mint::LEN; let mint\_rent \= client .get\_minimum\_balance\_for\_rent\_exemption(mint\_space) .await?; // Instruction to create new account for mint (token program) let create\_account\_instruction \= create\_account( &fee\_payer.pubkey(), // payer &mint.pubkey(), // new account (mint) mint\_rent, // lamports mint\_space as u64, // space &token\_program\_id(), // program id ); // Instruction to initialize mint account data let initialize\_mint\_instruction \= initialize\_mint( &token\_program\_id(), &mint.pubkey(), // mint &fee\_payer.pubkey(), // mint authority Some(&fee\_payer.pubkey()), // freeze authority decimals, // decimals )?; // Calculate the associated token account address for fee\_payer let associated\_token\_address \= get\_associated\_token\_address( &fee\_payer.pubkey(), // owner &mint.pubkey(), // mint ); // Instruction to create associated token account let create\_ata\_instruction \= create\_associated\_token\_account( &fee\_payer.pubkey(), // funding address &fee\_payer.pubkey(), // wallet address &mint.pubkey(), // mint address &token\_program\_id(), // program id ); // Amount of tokens to mint (100 tokens with 2 decimals) let amount \= 100\_00; // Create mint\_to instruction to mint tokens to the associated token account let mint\_to\_instruction \= mint\_to( &token\_program\_id(), &mint.pubkey(), // mint &associated\_token\_address, // destination &fee\_payer.pubkey(), // authority &\[&fee\_payer.pubkey()\], // signer amount, // amount )?; // Create transaction and add instructions let transaction \= Transaction::new\_signed\_with\_payer( &\[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_ata\_instruction,\ \ mint\_to\_instruction,\ \ \], Some(&fee\_payer.pubkey()), &\[&fee\_payer, &mint\], latest\_blockhash, ); // Send and confirm transaction client.send\_and\_confirm\_transaction(&transaction).await?; // Amount of tokens to approve (1 token with 2 decimals) let approve\_amount \= 1\_00; // Create approve\_checked instruction let approve\_instruction \= approve\_checked( &token\_program\_id(), // program id &associated\_token\_address, // source token account &mint.pubkey(), // mint &delegate.pubkey(), // delegate &fee\_payer.pubkey(), // owner &\[&fee\_payer.pubkey()\], // signers approve\_amount, // amount decimals, // decimals )?; // Create transaction for approving delegate let transaction \= Transaction::new\_signed\_with\_payer( &\[approve\_instruction\], Some(&fee\_payer.pubkey()), &\[&fee\_payer\], latest\_blockhash, ); // Send and confirm transaction let transaction\_signature \= client.send\_and\_confirm\_transaction(&transaction).await?; let token \= client.get\_token\_account(&associated\_token\_address).await?; println!("Successfully approved delegate for 1.0 token"); println!("\\nDelegate Address: {}", delegate.pubkey()); println!("\\nToken Account Address: {}", associated\_token\_address); if let Some(token) \= token { println!("{:#?}", token); } println!("Transaction Signature: {}", transaction\_signature); Ok(()) } Console RunClick to execute the code. ### [Python](https://solana.com/docs/tokens/basics/approve-delegate#python) Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import create\_account, CreateAccountParams from spl.token.instructions import ( initialize\_mint, InitializeMintParams, create\_associated\_token\_account, mint\_to\_checked, MintToCheckedParams, approve\_checked, ApproveCheckedParams, get\_associated\_token\_address ) from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID \# Constants DECIMALS \= 9 async def setup(rpc, mint\_authority): """ The setup function initializes the mint and associated token accounts, and mints tokens to said associated token account """ mint \= Keypair() space \= 82 \# getMintSize() equivalent for SPL Token \# Get minimum balance for rent exemption rent \= await rpc.get\_minimum\_balance\_for\_rent\_exemption(space) \# Create & initialize mint account create\_account\_instruction \= create\_account( CreateAccountParams( from\_pubkey\=mint\_authority.pubkey(), to\_pubkey\=mint.pubkey(), lamports\=rent.value, space\=space, owner\=TOKEN\_PROGRAM\_ID ) ) initialize\_mint\_instruction \= initialize\_mint( InitializeMintParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), decimals\=DECIMALS, mint\_authority\=mint\_authority.pubkey(), freeze\_authority\=None ) ) \# Create associated token account authority\_ata \= get\_associated\_token\_address( owner\=mint\_authority.pubkey(), mint\=mint.pubkey(), token\_program\_id\=TOKEN\_PROGRAM\_ID ) create\_authority\_ata\_instruction \= create\_associated\_token\_account( payer\=mint\_authority.pubkey(), owner\=mint\_authority.pubkey(), mint\=mint.pubkey() ) \# Mint to token account mint\_to\_instruction \= mint\_to\_checked( MintToCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), dest\=authority\_ata, mint\_authority\=mint\_authority.pubkey(), amount\=1\_000\_000\_000\_000, \# 1000 tokens decimals\=DECIMALS ) ) instructions \= \[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_authority\_ata\_instruction,\ \ mint\_to\_instruction\ \ \] \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority, mint\]) print("Setup transaction created successfully") print(f"Mint: {mint.pubkey()}") print(f"Authority ATA: {authority\_ata}") return { "mint": mint.pubkey(), "authority\_ata": authority\_ata } async def main(): rpc \= AsyncClient("http://localhost:8899") \# Constants mint\_authority \= Keypair() delegate \= Keypair() async with rpc: \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Setup mint and associated token accounts setup\_result \= await setup(rpc, mint\_authority) mint \= setup\_result\["mint"\] authority\_ata \= setup\_result\["authority\_ata"\] \# Create delegate instruction delegate\_instruction \= approve\_checked( ApproveCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, source\=authority\_ata, mint\=mint, delegate\=delegate.pubkey(), owner\=mint\_authority.pubkey(), amount\=1\_000\_000\_000, \# 1 token decimals\=DECIMALS ) ) \# Create transaction message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=\[delegate\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority\]) print(f"\\nDelegate Transaction:") print(f"Source: {authority\_ata}") print(f"Mint: {mint}") print(f"Delegate: {delegate.pubkey()}") print(f"Owner: {mint\_authority.pubkey()}") print(f"Amount: 1\_000\_000\_000 (1 token)") print(f"Decimals: {DECIMALS}") print(f"Delegation transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Python #!/usr/bin/env python3 import asyncio from solana.rpc.async\_api import AsyncClient from solders.keypair import Keypair from solders.transaction import VersionedTransaction from solders.message import MessageV0 from solders.system\_program import create\_account, CreateAccountParams from spl.token.instructions import ( initialize\_mint, InitializeMintParams, create\_associated\_token\_account, mint\_to\_checked, MintToCheckedParams, approve\_checked, ApproveCheckedParams, get\_associated\_token\_address ) from spl.token.constants import TOKEN\_PROGRAM\_ID, ASSOCIATED\_TOKEN\_PROGRAM\_ID \# Constants DECIMALS \= 9 async def setup(rpc, mint\_authority): """ The setup function initializes the mint and associated token accounts, and mints tokens to said associated token account """ mint \= Keypair() space \= 82 \# getMintSize() equivalent for SPL Token \# Get minimum balance for rent exemption rent \= await rpc.get\_minimum\_balance\_for\_rent\_exemption(space) \# Create & initialize mint account create\_account\_instruction \= create\_account( CreateAccountParams( from\_pubkey\=mint\_authority.pubkey(), to\_pubkey\=mint.pubkey(), lamports\=rent.value, space\=space, owner\=TOKEN\_PROGRAM\_ID ) ) initialize\_mint\_instruction \= initialize\_mint( InitializeMintParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), decimals\=DECIMALS, mint\_authority\=mint\_authority.pubkey(), freeze\_authority\=None ) ) \# Create associated token account authority\_ata \= get\_associated\_token\_address( owner\=mint\_authority.pubkey(), mint\=mint.pubkey(), token\_program\_id\=TOKEN\_PROGRAM\_ID ) create\_authority\_ata\_instruction \= create\_associated\_token\_account( payer\=mint\_authority.pubkey(), owner\=mint\_authority.pubkey(), mint\=mint.pubkey() ) \# Mint to token account mint\_to\_instruction \= mint\_to\_checked( MintToCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, mint\=mint.pubkey(), dest\=authority\_ata, mint\_authority\=mint\_authority.pubkey(), amount\=1\_000\_000\_000\_000, \# 1000 tokens decimals\=DECIMALS ) ) instructions \= \[\ \ create\_account\_instruction,\ \ initialize\_mint\_instruction,\ \ create\_authority\_ata\_instruction,\ \ mint\_to\_instruction\ \ \] \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Create message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=instructions, address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority, mint\]) print("Setup transaction created successfully") print(f"Mint: {mint.pubkey()}") print(f"Authority ATA: {authority\_ata}") return { "mint": mint.pubkey(), "authority\_ata": authority\_ata } async def main(): rpc \= AsyncClient("http://localhost:8899") \# Constants mint\_authority \= Keypair() delegate \= Keypair() async with rpc: \# Get latest blockhash latest\_blockhash \= await rpc.get\_latest\_blockhash() \# Setup mint and associated token accounts setup\_result \= await setup(rpc, mint\_authority) mint \= setup\_result\["mint"\] authority\_ata \= setup\_result\["authority\_ata"\] \# Create delegate instruction delegate\_instruction \= approve\_checked( ApproveCheckedParams( program\_id\=TOKEN\_PROGRAM\_ID, source\=authority\_ata, mint\=mint, delegate\=delegate.pubkey(), owner\=mint\_authority.pubkey(), amount\=1\_000\_000\_000, \# 1 token decimals\=DECIMALS ) ) \# Create transaction message transaction\_message \= MessageV0.try\_compile( payer\=mint\_authority.pubkey(), instructions\=\[delegate\_instruction\], address\_lookup\_table\_accounts\=\[\], recent\_blockhash\=latest\_blockhash.value.blockhash ) \# Create and sign transaction signed\_transaction \= VersionedTransaction(transaction\_message, \[mint\_authority\]) print(f"\\nDelegate Transaction:") print(f"Source: {authority\_ata}") print(f"Mint: {mint}") print(f"Delegate: {delegate.pubkey()}") print(f"Owner: {mint\_authority.pubkey()}") print(f"Amount: 1\_000\_000\_000 (1 token)") print(f"Decimals: {DECIMALS}") print(f"Delegation transaction created successfully") if \_\_name\_\_ \== "\_\_main\_\_": asyncio.run(main()) Console RunClick to execute the code. Is this page helpful? [Previous\ \ Transfer Tokens](https://solana.com/docs/tokens/basics/transfer-tokens) [Next\ \ Revoke Delegate](https://solana.com/docs/tokens/basics/revoke-delegate) ### Table of Contents [How to Approve delegate](https://solana.com/docs/tokens/basics/approve-delegate#how-to-approve-delegate) [Typescript](https://solana.com/docs/tokens/basics/approve-delegate#typescript) [Rust](https://solana.com/docs/tokens/basics/approve-delegate#rust) [Python](https://solana.com/docs/tokens/basics/approve-delegate#python) [Edit Page](https://github.com/solana-foundation/solana-com/blob/main/apps/docs/content/docs/en/tokens/basics/approve-delegate.mdx) Ask AI Managed by [](https://solana.com/) © 2026 Solana Foundation. All rights reserved. [](https://solana.com/youtube) [](https://solana.com/twitter) [](https://solana.com/discord) [](https://solana.com/reddit) [](https://solana.com/github) [](https://solana.com/telegram) en Solana * [Grants](https://solana.org/grants) * [Media Kit](https://solana.com/branding) * [Careers](https://jobs.solana.com/) * [Disclaimer](https://solana.com/tos) * [Privacy Policy](https://solana.com/privacy-policy) Get connected * [Blog](https://solana.com/news) * Newsletter ---
{wallet?.account.address.toString()}
Lamports: {balance.lamports?.toString() ?? "loading…"}
Loading…
RPC error
Signature: {transfer.signature}
{String(transfer.error)}
Signature: {signature}
{String(error)}