Writing to the Network

In the previous section, you learned how to read data from the Solana network by fetching accounts. Writing data to the Solana network requires a transaction. A transaction contains one or more instructions, and each instruction invokes a program.

Programs define the business logic for each instruction. When you send a transaction, the Solana runtime executes the transaction's instructions in order. Transactions are atomic. Either every instruction in the transaction succeeds, or the entire transaction fails.

The examples in this section show how to:

  1. Transfer SOL between accounts
  2. Create a new token mint

Transfer SOL

The example below transfers SOL from one account to another. Only the program designated as an account's owner can modify the account's data or deduct lamports from its balance. Wallet accounts are owned by the System Program, so transferring SOL between wallet accounts requires an instruction that invokes the System Program's transfer instruction. The source account must also sign the transaction.

Transfer SOL
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const receiver = await generateKeyPairSigner();
const transferInstruction = getTransferSolInstruction({
source: client.payer,
destination: receiver.address,
amount: lamports(10_000_000n)
});
const result = await client.sendTransaction([transferInstruction]);
console.log("Transaction Signature:", result.context.signature);
const { value: senderBalance } = await client.rpc
.getBalance(client.payer.address)
.send();
const { value: receiverBalance } = await client.rpc
.getBalance(receiver.address)
.send();
console.log("Sender Balance:", senderBalance);
console.log("Receiver Balance:", receiverBalance);
Console
Click to execute the code.

Create a Kit client for the local test validator. This snippet adds a payer signer, connects to the local RPC endpoint, enables airdrops, and funds the payer with test SOL for the transfer.

Client setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));

Generate a signer for the receiver. The sender is client.payer, which was created by generatedPayer() and funded by airdropPayer().

Receiver signer
const receiver = await generateKeyPairSigner();

The getTransferSolInstruction() helper creates a System Program instruction. The instruction transfers SOL from the source signer to the destination address for the specified amount of lamports.

Transfer instruction
const transferInstruction = getTransferSolInstruction({
source: client.payer,
destination: receiver.address,
amount: lamports(10_000_000n)
});

Call client.sendTransaction() with an array of instructions. The Kit client turns the instructions into one transaction, signs with the signers attached to the instructions, sends the transaction, and waits for confirmation.

Send transaction
const result = await client.sendTransaction([transferInstruction]);
console.log("Transaction Signature:", result.context.signature);

After the transaction is confirmed, fetch both balances using client.rpc.

Fetch balances
const { value: senderBalance } = await client.rpc
.getBalance(client.payer.address)
.send();
const { value: receiverBalance } = await client.rpc
.getBalance(receiver.address)
.send();

Create a Kit client for the local test validator. This snippet adds a payer signer, connects to the local RPC endpoint, enables airdrops, and funds the payer with test SOL for the transfer.

Client setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));

Generate a signer for the receiver. The sender is client.payer, which was created by generatedPayer() and funded by airdropPayer().

Receiver signer
const receiver = await generateKeyPairSigner();

The getTransferSolInstruction() helper creates a System Program instruction. The instruction transfers SOL from the source signer to the destination address for the specified amount of lamports.

Transfer instruction
const transferInstruction = getTransferSolInstruction({
source: client.payer,
destination: receiver.address,
amount: lamports(10_000_000n)
});

Call client.sendTransaction() with an array of instructions. The Kit client turns the instructions into one transaction, signs with the signers attached to the instructions, sends the transaction, and waits for confirmation.

Send transaction
const result = await client.sendTransaction([transferInstruction]);
console.log("Transaction Signature:", result.context.signature);

After the transaction is confirmed, fetch both balances using client.rpc.

Fetch balances
const { value: senderBalance } = await client.rpc
.getBalance(client.payer.address)
.send();
const { value: receiverBalance } = await client.rpc
.getBalance(receiver.address)
.send();
Transfer SOL
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));

Create a token

The example below creates a new token mint using the Token Extensions Program. A mint account is the account that defines a token's global settings, such as decimals, supply, mint authority, and freeze authority.

Creating a mint account requires two instructions:

  1. Invoke the System Program to create a new account owned by the Token Extensions Program.
  2. Invoke the Token Extensions Program to initialize that account as a mint.
Create mint account
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
fetchMint,
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();
const space = BigInt(getMintSize());
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();
const createAccountInstruction = getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
space,
lamports: rent,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const result = await client.sendTransaction([
createAccountInstruction,
initializeMintInstruction
]);
console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", result.context.signature);
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
Console
Click to execute the code.

Create and fund a Kit client, then generate a signer to use as the address of the new mint account. The client payer funds account creation and pays the transaction fee.

Client and mint setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();

Calculate the mint account size in bytes, then make an RPC request to calculate the lamports required to store that data in the account. This required balance is referred to as rent.

Mint account size and rent
const space = BigInt(getMintSize());
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

The first instruction invokes the System Program. The instruction uses the payer to fund a newAccount, allocates the mint account space, transfers the rent-exempt lamports, and assigns ownership to the programAddress.

Create account instruction
const createAccountInstruction = getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
space,
lamports: rent,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

The second instruction invokes the Token Extensions Program. The instruction initializes the mint address with a decimals value, a mintAuthority, a freezeAuthority, and specifies the tokenProgram that owns the mint account.

Initialize mint instruction
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

Send both instructions in one transaction. The create account instruction must come before the initialize mint instruction because the mint account must exist before the Token Extensions Program can write mint data to the account.

Send transaction
const result = await client.sendTransaction([
createAccountInstruction,
initializeMintInstruction
]);

After the transaction is confirmed, fetch the mint account.

Fetch mint account
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);

Create and fund a Kit client, then generate a signer to use as the address of the new mint account. The client payer funds account creation and pays the transaction fee.

Client and mint setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();

Calculate the mint account size in bytes, then make an RPC request to calculate the lamports required to store that data in the account. This required balance is referred to as rent.

Mint account size and rent
const space = BigInt(getMintSize());
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

The first instruction invokes the System Program. The instruction uses the payer to fund a newAccount, allocates the mint account space, transfers the rent-exempt lamports, and assigns ownership to the programAddress.

Create account instruction
const createAccountInstruction = getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
space,
lamports: rent,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

The second instruction invokes the Token Extensions Program. The instruction initializes the mint address with a decimals value, a mintAuthority, a freezeAuthority, and specifies the tokenProgram that owns the mint account.

Initialize mint instruction
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

Send both instructions in one transaction. The create account instruction must come before the initialize mint instruction because the mint account must exist before the Token Extensions Program can write mint data to the account.

Send transaction
const result = await client.sendTransaction([
createAccountInstruction,
initializeMintInstruction
]);

After the transaction is confirmed, fetch the mint account.

Fetch mint account
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
Create mint account
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
fetchMint,
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();

Is this page helpful?

Table of Contents

Edit Page
© 2026 Solana Foundation. All rights reserved.