Accounts
How to create a system account
Create an account that the System Program owns. The Solana runtime will grant the owner of an account, access to write to its data or transfer lamports. When creating an account, we have to preallocate a fixed storage space in bytes (space
) and enough lamports to cover the rent. Rent is a cost incurred to keep accounts alive on Solana.
import {
SystemProgram,
Keypair,
Transaction,
sendAndConfirmTransaction,
Connection,
clusterApiUrl,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const fromPubkey = Keypair.generate();
// Airdrop SOL for transferring lamports to the created account
const airdropSignature = await connection.requestAirdrop(
fromPubkey.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(airdropSignature);
// amount of space to reserve for the account
const space = 0;
// Seed the created account with lamports for rent exemption
const rentExemptionAmount =
await connection.getMinimumBalanceForRentExemption(space);
const newAccountPubkey = Keypair.generate();
const createAccountParams = {
fromPubkey: fromPubkey.publicKey,
newAccountPubkey: newAccountPubkey.publicKey,
lamports: rentExemptionAmount,
space,
programId: SystemProgram.programId,
};
const createAccountTransaction = new Transaction().add(
SystemProgram.createAccount(createAccountParams)
);
await sendAndConfirmTransaction(connection, createAccountTransaction, [
fromPubkey,
newAccountPubkey,
]);
})();
const createAccountParams = {
fromPubkey: fromKeypair.publicKey,
newAccountPubkey: newAccountKeypair.publicKey,
lamports: rentExemptionAmount,
space,
programId: SystemProgram.programId,
};
const createAccountTransaction = new Transaction().add(
SystemProgram.createAccount(createAccountParams)
);
await sendAndConfirmTransaction(connection, createAccountTransaction, [
fromKeypair,
newAccountKeypair,
]);
use solana_client::rpc_client::RpcClient;
use solana_program::system_instruction;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::native_token::LAMPORTS_PER_SOL;
use solana_sdk::signature::{Keypair, Signer};
fn main() {
let rpc_url = String::from("https://api.devnet.solana.com");
let connection = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
let from_keypair = Keypair::new();
let from_pubkey = Signer::pubkey(&from_keypair);
match connection.request_airdrop(&from_pubkey, LAMPORTS_PER_SOL) {
Ok(sig) => loop {
if let Ok(confirmed) = connection.confirm_transaction(&sig) {
if confirmed {
println!("Transaction: {} Status: {}", sig, confirmed);
break;
}
}
},
Err(_) => println!("Error requesting airdrop"),
};
let space = 0;
let rent_exemption_amount = connection
.get_minimum_balance_for_rent_exemption(space)
.unwrap();
let new_account_keypair = Keypair::new();
let new_account_pubkey = Signer::pubkey(&new_account_keypair);
let create_account_ix = system_instruction::create_account(
&from_pubkey,
&new_account_pubkey,
rent_exemption_amount,
space as u64,
&from_pubkey,
);
let (recent_blockhash, _) = connection.get_recent_blockhash().unwrap();
let create_account_tx = solana_sdk::transaction::Transaction::new_signed_with_payer(
&[create_account_ix],
Some(&from_pubkey),
&[&from_keypair, &new_account_keypair],
recent_blockhash,
);
match connection.send_and_confirm_transaction(&create_account_tx) {
Ok(sig) => loop {
if let Ok(confirmed) = connection.confirm_transaction(&sig) {
if confirmed {
println!("Transaction: {} Status: {}", sig, confirmed);
break;
}
}
},
Err(_) => println!("Error creating system account"),
};
}
let create_account_ix = system_instruction::create_account(
&from_pubkey,
&new_account_pubkey,
rent_exemption_amount,
space as u64,
&from_pubkey,
);
let (recent_blockhash, _) = connection.get_recent_blockhash().unwrap();
let create_account_tx = solana_sdk::transaction::Transaction::new_signed_with_payer(
&[create_account_ix],
Some(&from_pubkey),
&[&from_keypair, &new_account_keypair],
recent_blockhash,
);
match connection.send_and_confirm_transaction(&create_account_tx) {
Ok(sig) => loop {
if let Ok(confirmed) = connection.confirm_transaction(&sig) {
if confirmed {
println!("Transaction: {} Status: {}", sig, confirmed);
break;
}
}
},
Err(_) => println!("Error creating system account"),
};
How to calculate account cost
Keeping accounts alive on Solana incurs a storage cost called rent. An account can be made entirely exempt from rent collection by depositing at least two years worth of rent. For the calculation, you need to consider the amount of data you intend to store in the account.
import { Connection, clusterApiUrl } from "@solana/web3.js";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// length of data in the account to calculate rent for
const dataLength = 1500;
const rentExemptionAmount =
await connection.getMinimumBalanceForRentExemption(dataLength);
console.log({
rentExemptionAmount,
});
})();
use solana_client::rpc_client::RpcClient;
use solana_sdk::commitment_config::CommitmentConfig;
fn main() {
let rpc_url = String::from("https://api.devnet.solana.com");
let connection = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
let data_length = 1500;
let rent_exemption_amount = connection
.get_minimum_balance_for_rent_exemption(data_length)
.unwrap();
println!("rent exemption amount: {}", rent_exemption_amount);
}
solana rent 1500
How to create accounts with seeds
You can use createAccountWithSeed
to manage your accounts instead of creating a bunch of different keypair.
Generate
import { PublicKey, SystemProgram } from "@solana/web3.js";
(async () => {
let basePubkey = new PublicKey(
"G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY"
);
let seed = "robot001";
let programId = SystemProgram.programId;
console.log(
`${(
await PublicKey.createWithSeed(basePubkey, seed, programId)
).toBase58()}`
);
})();
PublicKey.createWithSeed(basePubkey, seed, programId);
use solana_program::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, Signer};
fn main() {
let base_pubkey = Keypair::new().pubkey();
let seed = "robot001";
let program_id = solana_program::system_program::id();
let derived_pubkey = Pubkey::create_with_seed(&base_pubkey, seed, &program_id).unwrap();
println!("account pubkey: {:?}", derived_pubkey);
}
use solana_program::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, Signer};
fn main() {
let base_pubkey = Keypair::new().pubkey();
let seed = "robot001";
let program_id = solana_program::system_program::id();
let derived_pubkey = Pubkey::create_with_seed(&base_pubkey, seed, &program_id).unwrap();
println!("account pubkey: {:?}", derived_pubkey);
}
Create
import {
PublicKey,
SystemProgram,
Connection,
clusterApiUrl,
Transaction,
Keypair,
sendAndConfirmTransaction,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const base = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
let basePubkey = base.publicKey;
let seed = "robot001";
let programId = SystemProgram.programId;
let derived = await PublicKey.createWithSeed(basePubkey, seed, programId);
const tx = new Transaction().add(
SystemProgram.createAccountWithSeed({
fromPubkey: feePayer.publicKey, // funder
newAccountPubkey: derived,
basePubkey: basePubkey,
seed: seed,
lamports: 1e8, // 0.1 SOL
space: 0,
programId: programId,
})
);
console.log(
`txhash: ${await sendAndConfirmTransaction(connection, tx, [
feePayer,
base,
])}`
);
})();
const tx = new Transaction().add(
SystemProgram.createAccountWithSeed({
fromPubkey: feePayer.publicKey, // funder
newAccountPubkey: derived,
basePubkey: basePubkey,
seed: seed,
lamports: 1e8, // 0.1 SOL
space: 0,
programId: owner,
})
);
console.log(
`txhash: ${await sendAndConfirmTransaction(connection, tx, [feePayer, base])}`
);
use solana_client::rpc_client::RpcClient;
use solana_program::pubkey::Pubkey;
use solana_program::system_instruction;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::native_token::LAMPORTS_PER_SOL;
use solana_sdk::signature::{Keypair, Signer};
fn main() {
let rpc_url = String::from("https://api.devnet.solana.com");
let connection = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
let fee_payer_keypair = Keypair::new();
let fee_payer_pubkey = Signer::pubkey(&fee_payer_keypair);
let base_keypair = Keypair::new();
let base_pubkey = Signer::pubkey(&base_keypair);
let seed = "robot001";
let program_id = solana_program::system_program::id();
let derived_pubkey = Pubkey::create_with_seed(&base_pubkey, seed, &program_id).unwrap();
match connection.request_airdrop(&fee_payer_pubkey, LAMPORTS_PER_SOL) {
Ok(sig) => loop {
if let Ok(confirmed) = connection.confirm_transaction(&sig) {
if confirmed {
println!("Transaction: {} Status: {}", sig, confirmed);
break;
}
}
},
Err(_) => println!("Error requesting airdrop"),
};
let ix = system_instruction::create_account_with_seed(
&fee_payer_pubkey,
&derived_pubkey,
&base_pubkey,
seed,
LAMPORTS_PER_SOL / 10,
0,
&program_id,
);
let (recent_blockhash, _) = connection.get_recent_blockhash().unwrap();
let tx = solana_sdk::transaction::Transaction::new_signed_with_payer(
&[ix],
Some(&fee_payer_pubkey),
&[&fee_payer_keypair, &base_keypair],
recent_blockhash,
);
match connection.send_and_confirm_transaction(&tx) {
Ok(sig) => loop {
if let Ok(confirmed) = connection.confirm_transaction(&sig) {
if confirmed {
println!("Transaction: {} Status: {}", sig, confirmed);
break;
}
}
},
Err(_) => println!("Error creating account with seed"),
};
}
let derived_pubkey = Pubkey::create_with_seed(&base_pubkey, seed, &program_id).unwrap();
let ix = system_instruction::create_account_with_seed(
&fee_payer_pubkey,
&derived_pubkey,
&base_pubkey,
seed,
LAMPORTS_PER_SOL / 10,
0,
&program_id,
);
let tx = solana_sdk::transaction::Transaction::new_signed_with_payer(
&[ix],
Some(&fee_payer_pubkey),
&[&fee_payer_keypair, &base_keypair],
recent_blockhash,
);
Transfer
import {
PublicKey,
SystemProgram,
Connection,
clusterApiUrl,
Transaction,
Keypair,
sendAndConfirmTransaction,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import * as bs58 from "bs58";
(async () => {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// 5YNmS1R9nNSCDzb5a7mMJ1dwK9uHeAAF4CmPEwKgVWr8
const feePayer = Keypair.fromSecretKey(
bs58.decode(
"588FU4PktJWfGfxtzpAAXywSNt74AvtroVzGfKkVN1LwRuvHwKGr851uH8czM5qm4iqLbs1kKoMKtMJG4ATR7Ld2"
)
);
// G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY
const base = Keypair.fromSecretKey(
bs58.decode(
"4NMwxzmYj2uvHuq8xoqhY8RXg63KSVJM1DXkpbmkUY7YQWuoyQgFnnzn6yo3CMnqZasnNPNuAT2TLwQsCaKkUddp"
)
);
let basePubkey = base.publicKey;
let seed = "robot001";
let programId = SystemProgram.programId;
let derived = await PublicKey.createWithSeed(basePubkey, seed, programId);
const tx = new Transaction().add(
SystemProgram.transfer({
fromPubkey: derived,
basePubkey: basePubkey,
toPubkey: Keypair.generate().publicKey, // create a random receiver
lamports: 0.01 * LAMPORTS_PER_SOL,
seed: seed,
programId: programId,
})
);
console.log(
`txhash: ${await sendAndConfirmTransaction(connection, tx, [
feePayer,
base,
])}`
);
})();
const tx = new Transaction().add(
SystemProgram.transfer({
fromPubkey: derived,
basePubkey: basePubkey,
toPubkey: Keypair.generate().publicKey, // create a random receiver
lamports: 0.01 * LAMPORTS_PER_SOL,
seed: seed,
programId: programId,
})
);
console.log(
`txhash: ${await sendAndConfirmTransaction(connection, tx, [feePayer, base])}`
);
TIP
Only an account owned by system program can transfer via system program.
How to create PDAs
Program derived address(PDA) is like a normal address with the following differences:
- Falling off ed25519 curve
- Using program to sign instead of private key
Note: PDA accounts can only be created on the program. The address can be created client side.
TIP
Although PDA is derived by a program id, it doesn't means the PDA is owned by the same program. (Take an example, you can initialize your PDA as a token account which is an account owned by token program)
Generate a PDA
findProgramAddress
will add a extra byte at the end of your seed. It starts from 255 to 0 and returns the first off-curve public key. You will always get the same result if you pass the same program id and seed.
import { PublicKey } from "@solana/web3.js";
(async () => {
const programId = new PublicKey(
"G1DCNUQTSGHehwdLCAmRyAG8hf51eCHrLNUqkgGKYASj"
);
let [pda, bump] = await PublicKey.findProgramAddress(
[Buffer.from("test")],
programId
);
console.log(`bump: ${bump}, pubkey: ${pda.toBase58()}`);
// you will find the result is different from `createProgramAddress`.
// It is expected because the real seed we used to calculate is ["test" + bump]
})();
use solana_program::pubkey::Pubkey;
use std::str::FromStr;
fn main() {
let program_id = Pubkey::from_str("G1DCNUQTSGHehwdLCAmRyAG8hf51eCHrLNUqkgGKYASj").unwrap();
let (pda, bump_seed) = Pubkey::find_program_address(&[b"test"], &program_id);
println!("pda: {}, bump: {}", pda, bump_seed);
}
Create a PDA
Below is an example program for creating a PDA account owned by the program and an example for calling the program with the client.
Program
The below shows a single instruction system_instruction::create_account
that creates an account with allocated data size of space
, rent_lamports
amount of lamports for the derived PDA. This is signed with the PDA using invoke_signed
similar to as discussed above.
use solana_program::{
account_info::next_account_info, account_info::AccountInfo, entrypoint,
entrypoint::ProgramResult, program::invoke_signed, pubkey::Pubkey, system_instruction, sysvar::{rent::Rent, Sysvar}
};
entrypoint!(process_instruction);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let payer_account_info = next_account_info(account_info_iter)?;
let pda_account_info = next_account_info(account_info_iter)?;
let rent_sysvar_account_info = &Rent::from_account_info(next_account_info(account_info_iter)?)?;
// find space and minimum rent required for account
let space = instruction_data[0];
let bump = instruction_data[1];
let rent_lamports = rent_sysvar_account_info.minimum_balance(space.into());
invoke_signed(
&system_instruction::create_account(
&payer_account_info.key,
&pda_account_info.key,
rent_lamports,
space.into(),
program_id
),
&[
payer_account_info.clone(),
pda_account_info.clone()
],
&[&[&payer_account_info.key.as_ref(), &[bump]]]
)?;
Ok(())
}
invoke_signed(
&system_instruction::create_account(
&payer_account_info.key,
&pda_account_info.key,
rent_lamports,
space.into(),
program_id
),
&[
payer_account_info.clone(),
pda_account_info.clone()
],
&[&[&payer_account_info.key.as_ref(), &[bump]]]
)?;
Client
import {
clusterApiUrl,
Connection,
Keypair,
Transaction,
SystemProgram,
PublicKey,
TransactionInstruction,
LAMPORTS_PER_SOL,
SYSVAR_RENT_PUBKEY,
} from "@solana/web3.js";
(async () => {
// program id
const programId = new PublicKey(
"7ZP42kRwUQ2zgbqXoaXzAFaiQnDyp6swNktTSv8mNQGN"
);
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// setup fee payer
const feePayer = Keypair.generate();
const feePayerAirdropSignature = await connection.requestAirdrop(
feePayer.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(feePayerAirdropSignature);
// setup pda
let [pda, bump] = await PublicKey.findProgramAddress(
[feePayer.publicKey.toBuffer()],
programId
);
console.log(`bump: ${bump}, pubkey: ${pda.toBase58()}`);
const data_size = 0;
let tx = new Transaction().add(
new TransactionInstruction({
keys: [
{
pubkey: feePayer.publicKey,
isSigner: true,
isWritable: true,
},
{
pubkey: pda,
isSigner: false,
isWritable: true,
},
{
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false,
},
{
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
],
data: Buffer.from(new Uint8Array([data_size, bump])),
programId: programId,
})
);
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer])}`);
})();
let tx = new Transaction().add(
new TransactionInstruction({
keys: [
{
pubkey: feePayer.publicKey,
isSigner: true,
isWritable: true,
},
{
pubkey: pda,
isSigner: false,
isWritable: true,
},
{
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false,
},
{
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
],
data: Buffer.from(new Uint8Array([data_size, bump])),
programId: programId,
})
);
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer])}`);
How to sign with a PDA
PDAs can only be signed for within the program. Below is a program example of signing with a PDA and calling the program with the client.
Program
The below shows a single instruction that transfers SOL from a PDA that was derived by the seed escrow
to an account passed. invoke_signed
is used to sign with the PDA.
use solana_program::{
account_info::next_account_info, account_info::AccountInfo, entrypoint,
entrypoint::ProgramResult, program::invoke_signed, pubkey::Pubkey, system_instruction,
};
entrypoint!(process_instruction);
fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let pda_account_info = next_account_info(account_info_iter)?;
let to_account_info = next_account_info(account_info_iter)?;
let system_program_account_info = next_account_info(account_info_iter)?;
// pass bump seed for saving compute budget
let bump_seed = instruction_data[0];
invoke_signed(
&system_instruction::transfer(
&pda_account_info.key,
&to_account_info.key,
100_000_000, // 0.1 SOL
),
&[
pda_account_info.clone(),
to_account_info.clone(),
system_program_account_info.clone(),
],
&[&[b"escrow", &[bump_seed]]],
)?;
Ok(())
}
invoke_signed(
&system_instruction::transfer(
&pda_account_info.key,
&to_account_info.key,
100_000_000, // 0.1 SOL
),
&[
pda_account_info.clone(),
to_account_info.clone(),
system_program_account_info.clone(),
],
&[&[b"escrow", &[bump_seed]]],
)?;
Client
import {
clusterApiUrl,
Connection,
Keypair,
Transaction,
SystemProgram,
PublicKey,
TransactionInstruction,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
import * as bs58 from "bs58";
(async () => {
// program id
const programId = new PublicKey(
"4wQC2yuVt4rbcPeYLK8WngqbYLg7UAahVjRFrK3NBjP6"
);
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// setup fee payer
const feePayer = Keypair.generate();
const feePayerAirdropSignature = await connection.requestAirdrop(
feePayer.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(feePayerAirdropSignature);
// setup pda
let [pda, bump] = await PublicKey.findProgramAddress(
[Buffer.from("escrow")],
programId
);
console.log(`bump: ${bump}, pubkey: ${pda.toBase58()}`);
// require 1 SOL for the transfering in the program
const pdaAirdropSignature = await connection.requestAirdrop(
pda,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(pdaAirdropSignature);
// create a random `to`
const to = Keypair.generate();
console.log(`receiver: ${to.publicKey.toBase58()}`);
let tx = new Transaction().add(
new TransactionInstruction({
keys: [
{
pubkey: pda,
// Leave `false` here although we need a pda as a signer.
// It will be escalated on program if we use invoke_signed.
isSigner: false,
isWritable: true,
},
{
pubkey: to.publicKey,
isSigner: false,
isWritable: true,
},
{
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
],
data: Buffer.from(new Uint8Array([bump])),
programId: programId,
})
);
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer])}`);
})();
let tx = new Transaction().add(
new TransactionInstruction({
keys: [
{
pubkey: pda,
// Leave `false` here although we need a pda as a signer.
// It will be escalated on program if we use invoke_signed.
isSigner: false,
isWritable: true,
},
{
pubkey: to.publicKey,
isSigner: false,
isWritable: true,
},
{
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
],
data: Buffer.from(new Uint8Array([bump])),
programId: programId,
})
);
console.log(`txhash: ${await connection.sendTransaction(tx, [feePayer])}`);
How to get program accounts
Return all accounts owned by a program. Refer to the guides section for more information on getProgramAccounts
and its configuration.
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
(async () => {
const MY_PROGRAM_ID = new PublicKey(
"6a2GdmttJdanBkoHt7f4Kon4hfadx4UTUgJeRkCaiL3U"
);
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const accounts = await connection.getProgramAccounts(MY_PROGRAM_ID);
console.log(`Accounts for program ${MY_PROGRAM_ID}: `);
console.log(accounts);
/*
// Output
Accounts for program 6a2GdmttJdanBkoHt7f4Kon4hfadx4UTUgJeRkCaiL3U:
[
{
account: {
data: <Buffer 60 06 66 ca 2c 1d c7 85 04 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 fc>,
executable: false,
lamports: 1064880,
owner: [PublicKey],
rentEpoch: 228
},
pubkey: PublicKey {
_bn: <BN: 82fc5b91154dc5c840cb464ba6a89212d0fd789367c0a1488fb1941d78f9727a>
}
},
{
account: {
data: <Buffer 60 06 66 ca 2c 1d c7 85 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 fd>,
executable: false,
lamports: 1064880,
owner: [PublicKey],
rentEpoch: 229
},
pubkey: PublicKey {
_bn: <BN: 404dc1fe368cf194f20cf3c681a071c61893ced98f65cda12ba5a147e984e669>
}
}
]
*/
})();
use solana_client::rpc_client::RpcClient;
use solana_program::pubkey::Pubkey;
use solana_sdk::commitment_config::CommitmentConfig;
use std::str::FromStr;
fn main() {
let rpc_url = String::from("https://api.devnet.solana.com");
let connection = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
let program_id = Pubkey::from_str("6a2GdmttJdanBkoHt7f4Kon4hfadx4UTUgJeRkCaiL3U").unwrap();
let accounts = connection.get_program_accounts(&program_id).unwrap();
println!("accounts for {}, {:?}", program_id, accounts);
}
curl https://api.devnet.solana.com -X POST -H "Content-Type: application/json" -d '
{"jsonrpc":"2.0", "id":1, "method":"getProgramAccounts", "params":["6a2GdmttJdanBkoHt7f4Kon4hfadx4UTUgJeRkCaiL3U"]}
'
# Output
# {"jsonrpc":"2.0","result":[{"account":{"data":"fe2kiXpgfrjWQjCPX3n5MB339Ayqav75ej","executable":false,"lamports":1064880,"owner":"6a2GdmttJdanBkoHt7f4Kon4hfadx4UTUgJeRkCaiL3U","rentEpoch":228},"pubkey":"9pKBrUtJU9GNmct6T2BQtiKqvubtjS9D2if2bm1P8TQd"},{"account":{"data":"fe2kiXpgfrjVs7hiZJNVFsbJUuhXhFx3pQ","executable":false,"lamports":1064880,"owner":"6a2GdmttJdanBkoHt7f4Kon4hfadx4UTUgJeRkCaiL3U","rentEpoch":229},"pubkey":"5L1rztbopmgGMWPKb2efoGyhGnrBJm6K53Hf9S4nxdHr"}],"id":1}
How to close accounts
You can close an account (erase all stored data) by removing all SOL. (you can refer to rent for more information)
Program
use solana_program::{
account_info::next_account_info, account_info::AccountInfo, entrypoint,
entrypoint::ProgramResult, pubkey::Pubkey,
};
entrypoint!(process_instruction);
fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
let account_info_iter = &mut accounts.iter();
let source_account_info = next_account_info(account_info_iter)?;
let dest_account_info = next_account_info(account_info_iter)?;
let dest_starting_lamports = dest_account_info.lamports();
**dest_account_info.lamports.borrow_mut() = dest_starting_lamports
.checked_add(source_account_info.lamports())
.unwrap();
**source_account_info.lamports.borrow_mut() = 0;
let mut source_data = source_account_info.data.borrow_mut();
source_data.fill(0);
Ok(())
}
let dest_starting_lamports = dest_account_info.lamports();
**dest_account_info.lamports.borrow_mut() = dest_starting_lamports
.checked_add(source_account_info.lamports())
.unwrap();
**source_account_info.lamports.borrow_mut() = 0;
let mut source_data = source_account_info.data.borrow_mut();
source_data.fill(0);
Client
import {
Keypair,
Connection,
Transaction,
SystemProgram,
TransactionInstruction,
PublicKey,
clusterApiUrl,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
(async function () {
// connection
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// setup fee payer
const feePayer = Keypair.generate();
const feePayerAirdropSignature = await connection.requestAirdrop(
feePayer.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(feePayerAirdropSignature);
// remember to deploy your program first
const programId = new PublicKey(
"An47uBJ8kY7hzKPzDyRoFSsDHkZFY9vkfUGpTViWqLFz"
);
// 1. create an account to your program
let newAccountKeypair = Keypair.generate();
console.log(`new account: ${newAccountKeypair.publicKey.toBase58()}`);
let createNewAccountTx = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: newAccountKeypair.publicKey,
lamports: 1e8, // 0.1 SOL
space: 10, // a random value
programId: programId,
})
);
console.log(
`create account txhash: ${await connection.sendTransaction(
createNewAccountTx,
[feePayer, newAccountKeypair]
)}`
);
// 2. close your account
let closeAccountTx = new Transaction().add(
new TransactionInstruction({
keys: [
{
pubkey: newAccountKeypair.publicKey,
isSigner: false,
isWritable: true,
},
{
pubkey: feePayer.publicKey,
isSigner: false,
isWritable: true,
},
],
programId: programId,
})
);
console.log(
`close account txhash: ${await connection.sendTransaction(closeAccountTx, [
feePayer,
])}`
);
})();
// 1. create an account to your program
let createNewAccountTx = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: feePayer.publicKey,
newAccountPubkey: newAccountKeypair.publicKey,
lamports: 1e8, // 0.1 SOL
space: 10, // a random value
programId: programId,
})
);
// 2. close your account
let closeAccountTx = new Transaction().add(
new TransactionInstruction({
keys: [
{
pubkey: newAccountKeypair.publicKey,
isSigner: false,
isWritable: true,
},
{
pubkey: feePayer.publicKey,
isSigner: false,
isWritable: true,
},
],
programId: programId,
})
);
import {
createCloseAccountInstruction,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import { PublicKey, Transaction } from "@solana/web3.js";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
import { WalletNotConnectedError } from "@solana/wallet-adapter-base";
import React from "react";
// Utility function to find the associated token address
function findAssociatedTokenAddress(
walletAddress: PublicKey,
tokenMintAddress: PublicKey
): PublicKey {
return PublicKey.findProgramAddressSync(
[
walletAddress.toBuffer(),
TOKEN_PROGRAM_ID.toBuffer(),
tokenMintAddress.toBuffer(),
],
new PublicKey("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")
)[0];
}
// Main functional component
export default function CloseTokenAccount() {
const { publicKey, sendTransaction } = useWallet();
const { connection } = useConnection();
// Function to close the account
async function closeAcc() {
if (!publicKey) throw new WalletNotConnectedError();
try {
// Define the token address and associated token program id
const tokenAddress = new PublicKey(
"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" // -> BONK
);
// Get the associated token address
const ATA = findAssociatedTokenAddress(
publicKey!,
tokenAddress
).toBase58();
// Create a transaction to close the account
const transaction = new Transaction(
await connection.getLatestBlockhash()
).add(
createCloseAccountInstruction(
new PublicKey(ATA),
publicKey!,
publicKey!
)
);
// Send and confirm the transaction
const signature = await sendTransaction(transaction, connection);
await connection.confirmTransaction({
...(await connection.getLatestBlockhash()),
signature,
});
} catch (error) {
console.error("Error closing account:", error);
// Handle error appropriately, e.g., show a user-friendly error message
}
}
// Render the main component
return (
<button onClick={closeAcc} disabled={!publicKey}>
Close Account
</button>
);
}
async function closeAcc() {
if (!publicKey) throw new WalletNotConnectedError();
try {
// Define the token address and associated token program id
const tokenAddress = new PublicKey(
"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" // -> BONK
);
// Get the associated token address
const ATA = findAssociatedTokenAddress(publicKey!, tokenAddress).toBase58();
// Create a transaction to close the account
const transaction = new Transaction(
await connection.getLatestBlockhash()
).add(
createCloseAccountInstruction(new PublicKey(ATA), publicKey!, publicKey!)
);
// Send and confirm the transaction
const signature = await sendTransaction(transaction, connection);
await connection.confirmTransaction({
...(await connection.getLatestBlockhash()),
signature,
});
} catch (error) {
console.error("Error closing account:", error);
// Handle error appropriately, e.g., show a user-friendly error message
}
}
How to get account balance
import {
clusterApiUrl,
Connection,
PublicKey,
LAMPORTS_PER_SOL,
} from "@solana/web3.js";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
let wallet = new PublicKey("G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY");
console.log(
`${(await connection.getBalance(wallet)) / LAMPORTS_PER_SOL} SOL`
);
})();
console.log(`${(await connection.getBalance(wallet)) / LAMPORTS_PER_SOL} SOL`);
use solana_client::rpc_client::RpcClient;
use solana_program::native_token::LAMPORTS_PER_SOL;
use solana_program::pubkey::Pubkey;
use solana_sdk::commitment_config::CommitmentConfig;
use std::str::FromStr;
fn main() {
let rpc_url = String::from("https://api.devnet.solana.com");
let connection = RpcClient::new_with_commitment(rpc_url, CommitmentConfig::confirmed());
let wallet = Pubkey::from_str("G2FAbFQPFa5qKXCetoFZQEvF9BVvCKbvUZvodpVidnoY").unwrap();
let balance = connection.get_balance(&wallet).unwrap();
println!(
"The account {}, has {} SOL ",
wallet,
balance / LAMPORTS_PER_SOL
);
}
connection.get_balance(&wallet).unwrap();
from solders.keypair import Keypair
from solana.rpc.api import Client
client = Client("https://api.devnet.solana.com")
key_pair = Keypair()
public_key = key_pair.pubkey()
print(client.get_balance(public_key))
client = Client("https://api.devnet.solana.com")
key_pair = Keypair()
public_key = key_pair.pubkey()
client.get_balance(public_key)
// clang++ get_balance.cpp -o get_balance -std=c++17 -lssl -lcrypto -lsodium
#include "solana.hpp"
using namespace many::solana;
int main() {
Connection connection("https://api.devnet.solana.com");
auto key_pair = Keypair::generate();
auto public_key = key_pair.public_key;
std::cout << "public_key = " << public_key.to_base58() << std::endl;
uint64_t balance = connection.get_balance(public_key).unwrap();
std::cout << "balance = " << balance << std::endl;
return 0;
}
Connection connection("https://api.devnet.solana.com");
auto key_pair = Keypair::generate();
auto public_key = key_pair.public_key;
uint64_t balance = connection.get_balance(public_key).unwrap();
TIP
If you want to get a token balance, you will need to know the address of token account. For more information, see Token References