Cuentas
Cómo crear una cuenta del sistema
Crea una cuenta del sistema que pertenezca al programa System Program. El runtime de Solana dará acceso al dueño de la cuenta a escribir datos y transferir lamports. Cuando se crea una cuenta, debemos definir un espacio de almacenamiento en bytes (space
) y lamports suficientes para cubrir la renta. La renta (Rent) es un costo en Solana para mantener las cuentas activas.
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"),
};
Cómo calcular el costo de una cuenta
Mantener activas las cuentas en Solana incurre en un costo de almacenamiento llamado renta (Rent). Una cuenta puede quedar completamente exenta del cobro del alquiler mediante el depósito de al menos dos años de alquiler. Para el cálculo hay que tener en cuenta la cantidad de datos que pretende almacenar en la cuenta.
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
Cómo crear cuentas con semillas
Puedes usar createAccountWithSeed
para crear cuentas en vez de crear diferentes cuentas con diferentes pares de llaves.
Generar
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);
}
Crear
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,
);
Transferir
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.
Cómo crear PDAs
Las cuentas derivadas de programa o Program derived address(PDA) son como cuentas normales con las siguientes diferencias:
- Salen de la curva ed25519
- El programa es el que firma en vez de una llave privada
Nota: Las cuentas derivadas de programa solo pueden ser creadas en los programas. La dirección puede creada del lado del cliente.
TIP
Aunque la cuenta derivada del programa (PDA) se deriva de un id de programa, no significa que la PDA sea propiedad del mismo programa. Por ejemplo, puedes crear un PDA como una cuenta de token, la cual es propiedad del programa token
Generar una cuenta derivada de programa (PDA)
findProgramAddress
agregará un byte adicional al final de su semilla. Comienza de 255 a 0 y devuelve la primera clave pública fuera de la curva. Siempre obtendrá el mismo resultado si pasa la misma identificación del programa y semilla
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);
}
Crear una cuenta derivada de programa (PDA)
A continuación verás un programa ejemplo para crear una cuenta derivada de programa y un ejemplo de cómo llamar al programa desde el cliente.
Programa
A continuación se muestra una única instrucción system_instruction::create_account
que crea una cuenta con un tamaño de datos asignado de space
, rent_lamports
cantidad de lamports para la cuenta derivada de programa. Esto se firma con la cuenta derivada del programa usando invoke_signed
similar a como lo vimos anteriormente.
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]]]
)?;
Cliente
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])}`);
Cómo firmar con una cuenta derivada de programa (PDA)
Las cuentas derivadas de programa (PDA) solo se pueden firmar dentro del programa. A continuación se muestra un programa ejemplo de firma con una PDA y una llamada al programa con el cliente.
Programa
A continuación se muestra una única instrucción que transfiere SOL desde una PDA que fue derivada con la semilla escrow
a una cuenta que se envía. invoke_signed
es usado para firmar con la cuenta derivada de programa (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]]],
)?;
Cliente
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])}`);
Cómo obtener cuentas de programas
Retorna todas las cuentas derivadas de programa que es dueño un programa. Revisa la sección Guías para más información de getProgramAccounts
y su configuración.
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}
Cómo cerrar cuentas
Puedes cerrar una cuenta y borrar todos sus datos al eliminar todo el SOL. Puedes ver la renta (rent) para más información
Programa
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,
})
);
Cómo obtener el balance de una cuenta
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
Si deseas obtener el saldo de un token, deberás conocer la dirección de la cuenta de token. Para obtener más información, consulte Referencias de tokens