Escribiendo en la red

En la sección anterior, aprendiste cómo leer datos de la red de Solana mediante la consulta de cuentas. Para escribir datos en la red de Solana se necesita una transacción. Una transacción contiene una o más instrucciones, y cada instrucción invoca un programa.

Los programas definen la lógica de negocio de cada instrucción. Cuando envías una transacción, el runtime de Solana ejecuta las instrucciones de la transacción en orden. Las transacciones son atómicas: o todas las instrucciones de la transacción se ejecutan correctamente, o la transacción completa falla.

Los ejemplos de esta sección muestran cómo:

  1. Transferir SOL entre cuentas
  2. Crear un nuevo token mint

Transferir SOL

El siguiente ejemplo transfiere SOL de una cuenta a otra. Solo el programa designado como propietario de una cuenta puede modificar los datos de esa cuenta o deducir lamports de su saldo. Las cuentas de billetera son propiedad del System Program, por lo que transferir SOL entre cuentas de billetera requiere una instrucción que invoque la instrucción transfer del System Program. La cuenta de origen también debe firmar la transacción.

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.

Crea un cliente de Kit para el validator de pruebas local. Este fragmento añade un firmante pagador, se conecta al endpoint RPC local, habilita los airdrops y financia al pagador con SOL de prueba para la transferencia.

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)));

Genera un firmante para el receptor. El remitente es client.payer, que fue creado por generatedPayer() y financiado por airdropPayer().

Receiver signer
const receiver = await generateKeyPairSigner();

El helper getTransferSolInstruction() crea una instrucción de System Program. La instrucción transfiere SOL desde el firmante source hacia la dirección destination por la cantidad especificada de amount lamports.

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

Llama a client.sendTransaction() con un array de instrucciones. El cliente de Kit convierte las instrucciones en una sola transacción, firma con los firmantes adjuntos a las instrucciones, envía la transacción y espera la confirmación.

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

Después de que la transacción sea confirmada, obtén ambos saldos usando 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();

Crea un cliente de Kit para el validator de pruebas local. Este fragmento añade un firmante pagador, se conecta al endpoint RPC local, habilita los airdrops y financia al pagador con SOL de prueba para la transferencia.

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)));

Genera un firmante para el receptor. El remitente es client.payer, que fue creado por generatedPayer() y financiado por airdropPayer().

Receiver signer
const receiver = await generateKeyPairSigner();

El helper getTransferSolInstruction() crea una instrucción de System Program. La instrucción transfiere SOL desde el firmante source hacia la dirección destination por la cantidad especificada de amount lamports.

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

Llama a client.sendTransaction() con un array de instrucciones. El cliente de Kit convierte las instrucciones en una sola transacción, firma con los firmantes adjuntos a las instrucciones, envía la transacción y espera la confirmación.

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

Después de que la transacción sea confirmada, obtén ambos saldos usando 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)));

Crear un token

El siguiente ejemplo crea un nuevo mint de token usando el Token Extensions Program. Una mint account es la cuenta que define la configuración global de un token, como los decimales, el suministro, la autoridad de emisión y la autoridad de congelación.

Crear una mint account requiere dos instrucciones:

  1. Invocar el System Program para crear una nueva cuenta propiedad del Token Extensions Program.
  2. Invocar el Token Extensions Program para inicializar esa cuenta como un 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.

Crea y financia un cliente Kit, luego genera un firmante para usar como dirección del nuevo mint account. El pagador del cliente financia la creación de la cuenta y paga la comisión de la transacción.

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();

Calcula el tamaño del mint account en bytes, luego realiza una solicitud RPC para calcular los lamports necesarios para almacenar esos datos en la cuenta. Este saldo requerido se denomina rent.

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

La primera instrucción invoca el System Program. La instrucción usa el payer para financiar una newAccount, asigna el space del mint account, transfiere los lamports de exención de rent, y asigna la propiedad al programAddress.

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

La segunda instrucción invoca el Token Extensions Program. La instrucción inicializa la dirección del mint con un valor de decimals, una mintAuthority, una freezeAuthority, y especifica el tokenProgram que posee el 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
});

Envía ambas instrucciones en una sola transacción. La instrucción de creación de cuenta debe ir antes de la instrucción de inicialización del mint porque el mint account debe existir antes de que el Token Extensions Program pueda escribir los datos del mint en la cuenta.

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

Una vez confirmada la transacción, obtén el mint account.

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

Crea y financia un cliente Kit, luego genera un firmante para usar como dirección del nuevo mint account. El pagador del cliente financia la creación de la cuenta y paga la comisión de la transacción.

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();

Calcula el tamaño del mint account en bytes, luego realiza una solicitud RPC para calcular los lamports necesarios para almacenar esos datos en la cuenta. Este saldo requerido se denomina rent.

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

La primera instrucción invoca el System Program. La instrucción usa el payer para financiar una newAccount, asigna el space del mint account, transfiere los lamports de exención de rent, y asigna la propiedad al programAddress.

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

La segunda instrucción invoca el Token Extensions Program. La instrucción inicializa la dirección del mint con un valor de decimals, una mintAuthority, una freezeAuthority, y especifica el tokenProgram que posee el 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
});

Envía ambas instrucciones en una sola transacción. La instrucción de creación de cuenta debe ir antes de la instrucción de inicialización del mint porque el mint account debe existir antes de que el Token Extensions Program pueda escribir los datos del mint en la cuenta.

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

Una vez confirmada la transacción, obtén el 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();

Estos ejemplos usan generatedPayer() para crear un keypair desechable para pruebas locales. Las aplicaciones en producción nunca deben almacenar claves privadas en texto plano dentro del código — delega la firma a un backend de gestión de claves. Consulta Firma en Producción.

Is this page helpful?

Tabla de Contenidos

Editar Página