Saltearse al contenido

Tu Primera Transacción

Las transacciones son la forma fundamental de cambiar datos en la blockchain de Aptos. Piensa en ellas como enviar un paquete: necesitas especificar qué estás enviando, a quién va dirigido, y luego rastrearlo hasta que se confirme la entrega. En términos de blockchain, las transacciones te permiten transferir monedas, llamar funciones de contratos inteligentes y actualizar el estado en cadena.

Este tutorial te guiará a través de la creación y envío de tu primera transacción en la blockchain de Aptos. Aprenderás cómo:

  1. Configurar tu entorno de desarrollo
  2. Crear cuentas de prueba y financiarlas
  3. Construir una transacción para transferir monedas
  4. Simular la transacción para estimar costos
  5. Firmar y enviar la transacción
  6. Verificar que la transacción se ejecutó exitosamente

Antes de poder crear transacciones, necesitamos configurar nuestro entorno de desarrollo con las herramientas y SDKs necesarias.

  1. Instalar el SDK de TypeScript

    Instala el SDK de TypeScript usando tu gestor de paquetes preferido:

    Ventana de terminal
    npm install @aptos-labs/ts-sdk
  2. Crear un directorio de proyecto

    Crea un nuevo directorio para tu proyecto:

    Ventana de terminal
    mkdir mi-primera-transaccion
    cd mi-primera-transaccion
  3. Crear un nuevo archivo

    Crea un nuevo archivo llamado transaction.ts:

    Ventana de terminal
    touch transaction.ts

En blockchain, todas las transacciones deben provenir de una cuenta. Vamos a crear dos cuentas de prueba: una para enviar monedas (Alice) y otra para recibirlas (Bob).

  1. Configurar el cliente

    Primero, necesitamos inicializar el cliente de Aptos que se conectará a la blockchain. Abre transaction.ts en tu editor y agrega:

    import {
    Account,
    Aptos,
    AptosConfig,
    Network,
    } from "@aptos-labs/ts-sdk";
    async function main() {
    // Inicializar el cliente de Aptos
    const config = new AptosConfig({ network: Network.DEVNET });
    const aptos = new Aptos(config);
    console.log("Conectado a Aptos devnet");
    // Más código irá aquí
    }
    main().catch(console.error);
  2. Generar cuentas

    Agrega este código dentro de tu función main() para crear dos cuentas - Alice (remitente) y Bob (receptor):

    // Generar dos cuentas
    const alice = Account.generate();
    const bob = Account.generate();
    console.log("=== Direcciones ===");
    console.log(`Dirección de Alice: ${alice.accountAddress}`);
    console.log(`Dirección de Bob: ${bob.accountAddress}`);
  3. Financiar las cuentas

    Agrega este código después de generar las cuentas para obtener monedas de prueba del faucet:

    // Financiar las cuentas con APT de prueba del faucet de devnet
    console.log("\n=== Financiando cuentas ===");
    await aptos.fundAccount({
    accountAddress: alice.accountAddress,
    amount: 100_000_000, // 1 APT = 100,000,000 octas
    });
    console.log("Cuentas financiadas exitosamente");
    // Verificar saldos iniciales
    const aliceBalance = await aptos.getAccountAPTAmount({
    accountAddress: alice.accountAddress,
    });
    const bobBalance = await aptos.getAccountAPTAmount({
    accountAddress: bob.accountAddress,
    });
    console.log("\n=== Saldos Iniciales ===");
    console.log(`Alice: ${aliceBalance} octas`);
    console.log(`Bob: ${bobBalance} octas`);
  4. Ejecutar el código

    Vamos a probar nuestro código hasta ahora:

    Ventana de terminal
    npx ts-node transaction.ts

    Deberías ver una salida similar a:

    Conectado a Aptos devnet
    === Direcciones ===
    Dirección de Alice: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa
    Dirección de Bob: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b
    === Financiando cuentas ===
    Cuentas financiadas exitosamente
    === Saldos Iniciales ===
    Alice: 100000000 octas
    Bob: 0 octas

Ahora que tenemos cuentas financiadas, vamos a crear una transacción para transferir monedas de Alice a Bob. Esto es como llenar un formulario especificando qué quieres enviar y a quién.

  1. Entender la estructura de transacción

    Una transacción en Aptos tiene varios componentes clave:

    1. Remitente: La cuenta que inicia la transacción (Alice)
    2. Función: La función en cadena a llamar (en este caso, una transferencia de monedas)
    3. Argumentos: Datos necesarios para la función (dirección del destinatario y cantidad)
    4. Parámetros de gas: Cantidad máxima de gas y precio unitario de gas
    5. Tiempo de expiración: Cuando la transacción deja de ser válida si no se ejecuta
    6. Número de secuencia: Un contador que previene ataques de repetición
  2. Construir la transacción

    Vamos a agregar código para construir una transacción que transfiere 1000 octas de Alice a Bob:

    Agrega este código a tu función main():

    // 1. Construir la transacción
    console.log("\n=== 1. Construyendo la transacción ===");
    const transaction = await aptos.transaction.build.simple({
    sender: alice.accountAddress,
    data: {
    function: "0x1::aptos_account::transfer",
    functionArguments: [bob.accountAddress, 1000], // Transferir 1000 octas
    },
    });
    console.log("Transacción construida exitosamente");
    // Acceder a los detalles de la transacción desde la transacción raw
    const rawTxn = transaction.rawTransaction;
    console.log(`Remitente: ${rawTxn.sender}`);
    console.log(`Número de Secuencia: ${rawTxn.sequence_number}`);
    console.log(`Cantidad Máxima de Gas: ${rawTxn.max_gas_amount}`);
    console.log(`Precio Unitario de Gas: ${rawTxn.gas_unit_price}`);
    console.log(`Timestamp de Expiración: ${new Date(Number(rawTxn.expiration_timestamp_secs) * 1000).toISOString()}`);

Antes de enviar una transacción, es sabio simularla primero para estimar el costo de gas. Esto es como verificar los costos de envío antes de enviar un paquete.

  1. Simular la transacción

    Agrega este código después de construir la transacción:

    // 2. Simular la transacción
    console.log("\n=== 2. Simulando la transacción ===");
    const [simulationResult] = await aptos.transaction.simulate.simple({
    signerPublicKey: alice.publicKey,
    transaction,
    });
    const gasUsed = parseInt(simulationResult.gas_used);
    const gasUnitPrice = parseInt(simulationResult.gas_unit_price);
    console.log(`Unidades de gas estimadas: ${gasUsed}`);
    console.log(`Costo de gas estimado: ${gasUsed * gasUnitPrice} octas`);
    console.log(`La transacción ${simulationResult.success ? "tendría éxito" : "fallaría"}`);

Ahora que hemos construido y simulado la transacción, necesitamos firmarla con la clave privada de Alice y enviarla a la blockchain.

  1. Firmar la transacción

    Firmar prueba que Alice autorizó esta transacción:

    Agrega este código después de simular la transacción:

    // 3. Firmar la transacción
    console.log("\n=== 3. Firmando la transacción ===");
    const senderAuthenticator = aptos.transaction.sign({
    signer: alice,
    transaction,
    });
    console.log("Transacción firmada exitosamente");
  2. Enviar la transacción

    Agrega este código después de firmar la transacción para enviar la transacción firmada a la blockchain:

    // 4. Enviar la transacción
    console.log("\n=== 4. Enviando la transacción ===");
    const pendingTransaction = await aptos.transaction.submit.simple({
    transaction,
    senderAuthenticator,
    });
    console.log(`Transacción enviada con hash: ${pendingTransaction.hash}`);

Después de enviar una transacción, necesitamos esperar a que sea procesada por la blockchain. Esto es como esperar a que un paquete sea entregado.

  1. Esperar completación de la transacción

    Agrega este código después de enviar la transacción:

    // 5. Esperar a que la transacción se complete
    console.log("\n=== 5. Esperando completación de la transacción ===");
    const txnResult = await aptos.waitForTransaction({
    transactionHash: pendingTransaction.hash,
    });
    console.log(`Transacción completada con estado: ${txnResult.success ? "ÉXITO" : "FALLIDO"}`);
    // Si quieres ver más detalles sobre la transacción:
    console.log(`Estado VM: ${txnResult.vm_status}`);
    console.log(`Gas usado: ${txnResult.gas_used}`);
  2. Verificar los resultados

    Agrega este código después de esperar la transacción para verificar los saldos y confirmar que la transferencia funcionó:

    // Verificar saldos finales
    const aliceFinalBalance = await aptos.getAccountAPTAmount({
    accountAddress: alice.accountAddress,
    });
    const bobFinalBalance = await aptos.getAccountAPTAmount({
    accountAddress: bob.accountAddress,
    });
    console.log("\n=== Saldos Finales ===");
    console.log(`Alice: ${aliceFinalBalance} octas (gastó ${aliceBalance - aliceFinalBalance} octas en transferencia y gas)`);
    console.log(`Bob: ${bobFinalBalance} octas (recibió 1000 octas)`);
  3. Ejecutar el código completo

    Ventana de terminal
    npx ts-node transaction.ts

    Deberías ver una salida similar a:

    Conectado a Aptos devnet
    === Direcciones ===
    Dirección de Alice: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa
    Dirección de Bob: 0x7af2d6c93a2feafc9b69b5e8ad9d6b513b260f62f23f3a384a3a2e4a84694a9b
    === Financiando cuentas ===
    Cuentas financiadas exitosamente
    === Saldos Iniciales ===
    Alice: 100000000 octas
    Bob: 0 octas
    === 1. Construyendo la transacción ===
    Transacción construida exitosamente
    Remitente: 0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa
    Número de Secuencia: 0
    Cantidad Máxima de Gas: 20000
    Precio Unitario de Gas: 100
    Timestamp de Expiración: 2025-03-05T22:59:21.000Z
    === 2. Simulando la transacción ===
    Unidades de gas estimadas: 146
    Costo de gas estimado: 14600 octas
    La transacción tendría éxito
    === 3. Firmando la transacción ===
    Transacción firmada exitosamente
    === 4. Enviando la transacción ===
    Transacción enviada con hash: 0x3a8a3e34a1c64ad9d7636a3a827b7ec3bb12d73825b36fa06d425c5a3b42cccc
    === 5. Esperando completación de la transacción ===
    Transacción completada con estado: ÉXITO
    Estado VM: Ejecutado exitosamente
    Gas usado: 146
    === Saldos Finales ===
    Alice: 99984400 octas (gastó 15600 octas en transferencia y gas)
    Bob: 1000 octas (recibió 1000 octas)

7. (Opcional) Explora Tu Transacción En Cadena

Sección titulada «7. (Opcional) Explora Tu Transacción En Cadena»

Ahora que has ejecutado exitosamente una transacción, puedes explorarla en el Explorador de Aptos. Esto te ayudará a entender cómo se registran las transacciones en la blockchain y qué información está disponible públicamente.

  1. Copia el hash de tu transacción

    Desde la salida de tu terminal, copia el hash de transacción que se imprimió después del envío. Se ve algo como esto:

    Transacción enviada con hash: 0x3a8a3e34a1c64ad9d7636a3a827b7ec3bb12d73825b36fa06d425c5a3b42cccc
  2. Abre el Explorador de Aptos

    Ve al Explorador de Aptos.

  3. Asegúrate de estar en la red Devnet

    Busca “Devnet” en la esquina superior derecha, o cambia de red haciendo clic en el dropdown y seleccionando Devnet.

    Cambiando a la red Devnet en el Explorador de Aptos

  4. Busca tu transacción

    Pega el hash de tu transacción en la barra de búsqueda en el medio de la página.

  5. Ve los detalles de la transacción

    Espera a que aparezcan los resultados, luego haz clic en el hash de transacción para ver sus detalles.

    Deberías ver información sobre tu transacción, incluyendo:

    • Estado (debería ser “Success”)
    • Timestamp
    • Gas usado
    • Direcciones del remitente y destinatario
    • Cantidad transferida
  6. Explora más

    Desde la página de detalles de la transacción, puedes:

    • Hacer clic en las direcciones del remitente o destinatario para ver los detalles de sus cuentas
    • Ver los cambios exactos hechos al estado de la blockchain
    • Ver el payload y argumentos de la transacción

¡Felicitaciones! Has creado y ejecutado exitosamente tu primera transacción en la blockchain de Aptos. Aquí hay algunas sugerencias para qué explorar a continuación:

Aprende sobre transacciones más complejas:

Explora contratos inteligentes o conceptos básicos de cuentas:

¡Únete al Discord de Aptos y comparte lo que estás construyendo!

Las muestras completas de código a continuación combinan todos los fragmentos que hemos cubierto en este tutorial:

import { Account, Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
async function main() {
// Initialize the Aptos client
const config = new AptosConfig({ network: Network.DEVNET });
const aptos = new Aptos(config);
console.log("Connected to Aptos devnet");
// More code will go here
// Generate two accounts
const alice = Account.generate();
const bob = Account.generate();
console.log("=== Addresses ===");
console.log(`Alice's address: ${alice.accountAddress}`);
console.log(`Bob's address: ${bob.accountAddress}`);
// Fund the accounts with test APT from the devnet faucet
console.log("\n=== Funding accounts ===");
await aptos.fundAccount({
accountAddress: alice.accountAddress,
amount: 100_000_000, // 1 APT = 100,000,000 octas
});
await aptos.fundAccount({
accountAddress: bob.accountAddress,
amount: 0, // Bob starts with 0 APT
});
console.log("Accounts funded successfully");
// Check initial balances
const aliceBalance = await aptos.getAccountAPTAmount({
accountAddress: alice.accountAddress,
});
const bobBalance = await aptos.getAccountAPTAmount({
accountAddress: bob.accountAddress,
});
console.log("\n=== Initial Balances ===");
console.log(`Alice: ${aliceBalance} octas`);
console.log(`Bob: ${bobBalance} octas`);
// 1. Build the transaction
console.log("\n=== 1. Building the transaction ===");
const transaction = await aptos.transaction.build.simple({
sender: alice.accountAddress,
data: {
function: "0x1::aptos_account::transfer",
functionArguments: [bob.accountAddress, 1000], // Transfer 1000 octas
},
});
console.log("Transaction built successfully");
// Use type assertion to bypass TypeScript's type checking
const txnAny = transaction as any;
console.log(`Sender: ${alice.accountAddress}`); // Use the known sender address
console.log(`Sequence Number: ${txnAny.sequenceNumber || "N/A"}`);
console.log(`Max Gas Amount: ${txnAny.maxGasAmount || "N/A"}`);
console.log(`Gas Unit Price: ${txnAny.gasUnitPrice || "N/A"}`);
console.log(
`Expiration Timestamp: ${new Date(
Number(txnAny.expirationTimestampSecs || 0) * 1000
).toISOString()}`
);
// 2. Simulate the transaction
console.log("\n=== 2. Simulating the transaction ===");
const [simulationResult] = await aptos.transaction.simulate.simple({
signerPublicKey: alice.publicKey,
transaction,
});
console.log(`Estimated gas units: ${simulationResult.gas_used}`);
console.log(
`Estimated gas cost: ${
Number(simulationResult.gas_used) * Number(simulationResult.gas_unit_price)
} octas`
);
console.log(
`Transaction would ${simulationResult.success ? "succeed" : "fail"}`
);
// 3. Sign the transaction
console.log("\n=== 3. Signing the transaction ===");
const senderAuthenticator = aptos.transaction.sign({
signer: alice,
transaction,
});
console.log("Transaction signed successfully");
// Use type assertion to bypass TypeScript's type checking
const authAny = senderAuthenticator as any;
const signatureStr = typeof authAny.signature === 'string'
? authAny.signature
: JSON.stringify(authAny.signature || '');
console.log(`Signature: ${signatureStr.slice(0, 20)}...`);
// 4. Submit the transaction
console.log("\n=== 4. Submitting the transaction ===");
const pendingTransaction = await aptos.transaction.submit.simple({
transaction,
senderAuthenticator,
});
console.log(`Transaction submitted with hash: ${pendingTransaction.hash}`);
// 5. Wait for the transaction to complete
console.log("\n=== 5. Waiting for transaction completion ===");
const txnResult = await aptos.waitForTransaction({
transactionHash: pendingTransaction.hash,
});
console.log(
`Transaction completed with status: ${
txnResult.success ? "SUCCESS" : "FAILURE"
}`
);
// If you want to see more details about the transaction:
console.log(`VM Status: ${txnResult.vm_status}`);
console.log(`Gas used: ${txnResult.gas_used}`);
// Check final balances
const aliceFinalBalance = await aptos.getAccountAPTAmount({
accountAddress: alice.accountAddress,
});
const bobFinalBalance = await aptos.getAccountAPTAmount({
accountAddress: bob.accountAddress,
});
console.log("\n=== Final Balances ===");
console.log(
`Alice: ${aliceFinalBalance} octas (spent ${
aliceBalance - aliceFinalBalance
} octas on transfer and gas)`
);
console.log(`Bob: ${bobFinalBalance} octas (received 1000 octas)`);
}
main().catch(console.error);