Saltearse al contenido

SDK de Go - Construir Transacciones

Las transacciones te permiten cambiar datos en la cadena o activar eventos. Generalmente, las transacciones siguen 5 pasos desde la construcción hasta la ejecución en la cadena: construir, simular, firmar, enviar y esperar.

  1. Construir

    Construir una transacción es cómo especificas:

    1. La cuenta Sender.
      Esta cuenta normalmente paga las comisiones de gas por esta transacción. Ver Transacciones Patrocinadas para aprender cómo hacer que otra cuenta pague por las comisiones de transacción.
    2. La Function siendo llamada en la cadena.
      Este es el identificador para la función de entrada del contrato inteligente en la cadena que se activará cuando ejecutes esta transacción.
    3. Los ArgTypes y Args.
      Esto es cualquier dato que la función necesita para ejecutarse.

    Esto se puede hacer para una sola cuenta así:

    // 1. Construir transacción
    accountBytes, err := bcs.Serialize(&bob.Address)
    if err != nil {
    panic("Failed to serialize bob's address:" + err.Error())
    }
    amountBytes, err := bcs.SerializeU64(TransferAmount)
    if err != nil {
    panic("Failed to serialize transfer amount:" + err.Error())
    }
    rawTxn, err := client.BuildTransaction(alice.AccountAddress(), aptos.TransactionPayload{
    Payload: &aptos.EntryFunction{
    Module: aptos.ModuleId{
    Address: aptos.AccountOne,
    Name: "aptos_account",
    },
    Function: "transfer",
    ArgTypes: []aptos.TypeTag{},
    Args: [][]byte{
    accountBytes,
    amountBytes,
    },
    }},
    )

    Puedes personalizar la forma en que tu transacción se ejecuta pasando options al construir. Algunas de las opciones más comúnmente usadas son:

    1. MaxGasAmount - Esto limita la cantidad de gas que estás dispuesto a pagar para ejecutar esta transacción.
    2. GasUnitPrice - Puedes especificar un precio por gas mayor que el mínimo para ser ejecutado con mayor prioridad por la red de Aptos.
    3. ExpirationSeconds - Esto da un tiempo concreto en que la transacción debe ejecutarse o será cancelada.

    El SDK proporciona valores por defecto sensatos para estos valores si no se especifican explícitamente.

  2. Simular (Opcional)

    Cada transacción en la cadena de Aptos tiene una comisión de gas asociada con cuánto trabajo las máquinas de la red tienen que hacer al ejecutar la transacción. Para estimar el costo asociado con eso, puedes simular transacciones antes de comprometerlas.

    Puedes ejecutar la simulación usando aptos.SimulateTransaction así:

    // 2. Simular transacción (opcional)
    // Esto es útil para entender cuánto costará la transacción
    // y para asegurar que la transacción es válida antes de enviarla a la red
    // Esto es opcional, pero recomendado
    simulationResult, err := client.SimulateTransaction(rawTxn, alice)
    // If the fee looks ok, continue to signing!
  3. Firmar

    Una vez que la transacción está construida y los costos parecen razonables, puedes firmar la transacción con rawTransaction.SignedTransaction(). La firma debe venir de la cuenta sender.

    // 3. Firmar transacción
    signedTxn, err := rawTxn.SignedTransaction(alice)
  4. Enviar

    Ahora que la transacción está firmada, puedes enviarla a la red usando client.SubmitTransaction() así:

    // 4. Enviar transacción
    submitResult, err := client.SubmitTransaction(signedTxn)
  5. Esperar

    Finalmente, puedes esperar el resultado de la transacción usando client.WaitForTransaction() y especificando el hash de la transacción que acabas de enviar así:

    // 5. Esperar la transacción para completar
    txnHash := submitResult.Hash
    _, err = client.WaitForTransaction(txnHash)
// transfer_coin es un ejemplo de cómo hacer una transacción de transferencia de moneda en la forma más simple posible
package main
import (
"fmt"
"github.com/aptos-labs/aptos-go-sdk"
"github.com/aptos-labs/aptos-go-sdk/bcs"
)
const FundAmount = 100_000_000
const TransferAmount = 1_000
// example Este ejemplo muestra cómo hacer una transacción de transferencia de APT en la forma más simple posible
func example(networkConfig aptos.NetworkConfig) {
// Crear un cliente para Aptos
client, err := aptos.NewClient(networkConfig)
if err != nil {
panic("Failed to create client:" + err.Error())
}
// Crear cuentas localmente para alice y bob
alice, err := aptos.NewEd25519Account()
if err != nil {
panic("Failed to create alice:" + err.Error())
}
bob, err := aptos.NewEd25519Account()
if err != nil {
panic("Failed to create bob:" + err.Error())
}
fmt.Printf("\n=== Addresses ===\n")
fmt.Printf("Alice: %s\n", alice.Address.String())
fmt.Printf("Bob:%s\n", bob.Address.String())
// Fundear el remitente con el faucet para crearlo en la cadena
err = client.Fund(alice.Address, FundAmount)
if err != nil {
panic("Failed to fund alice:" + err.Error())
}
aliceBalance, err := client.AccountAPTBalance(alice.Address)
if err != nil {
panic("Failed to retrieve alice balance:" + err.Error())
}
bobBalance, err := client.AccountAPTBalance(bob.Address)
if err != nil {
panic("Failed to retrieve bob balance:" + err.Error())
}
fmt.Printf("\n=== Initial Balances ===\n")
fmt.Printf("Alice: %d\n", aliceBalance)
fmt.Printf("Bob:%d\n", bobBalance)
// 1. Construir transacción
accountBytes, err := bcs.Serialize(&bob.Address)
if err != nil {
panic("Failed to serialize bob's address:" + err.Error())
}
amountBytes, err := bcs.SerializeU64(TransferAmount)
if err != nil {
panic("Failed to serialize transfer amount:" + err.Error())
}
rawTxn, err := client.BuildTransaction(alice.AccountAddress(), aptos.TransactionPayload{
Payload: &aptos.EntryFunction{
Module: aptos.ModuleId{
Address: aptos.AccountOne,
Name: "aptos_account",
},
Function: "transfer",
ArgTypes: []aptos.TypeTag{},
Args: [][]byte{
accountBytes,
amountBytes,
},
}},
)
if err != nil {
panic("Failed to build transaction:" + err.Error())
}
// 2. Simular transacción (opcional)
// Esto es útil para entender cuánto costará la transacción
// y para asegurar que la transacción es válida antes de enviarla a la red
// Esto es opcional, pero recomendado
simulationResult, err := client.SimulateTransaction(rawTxn, alice)
if err != nil {
panic("Failed to simulate transaction:" + err.Error())
}
fmt.Printf("\n=== Simulation ===\n")
fmt.Printf("Gas unit price: %d\n", simulationResult[0].GasUnitPrice)
fmt.Printf("Gas used: %d\n", simulationResult[0].GasUsed)
fmt.Printf("Total gas fee: %d\n", simulationResult[0].GasUsed*simulationResult[0].GasUnitPrice)
fmt.Printf("Status: %s\n", simulationResult[0].VmStatus)
// 3. Firmar transacción
signedTxn, err := rawTxn.SignedTransaction(alice)
if err != nil {
panic("Failed to sign transaction:" + err.Error())
}
// 4. Enviar transacción
submitResult, err := client.SubmitTransaction(signedTxn)
if err != nil {
panic("Failed to submit transaction:" + err.Error())
}
txnHash := submitResult.Hash
// 5. Esperar la transacción para completar
_, err = client.WaitForTransaction(txnHash)
if err != nil {
panic("Failed to wait for transaction:" + err.Error())
}
// Check balances
aliceBalance, err = client.AccountAPTBalance(alice.Address)
if err != nil {
panic("Failed to retrieve alice balance:" + err.Error())
}
bobBalance, err = client.AccountAPTBalance(bob.Address)
if err != nil {
panic("Failed to retrieve bob balance:" + err.Error())
}
fmt.Printf("\n=== Intermediate Balances ===\n")
fmt.Printf("Alice: %d\n", aliceBalance)
fmt.Printf("Bob:%d\n", bobBalance)
// Ahora hazlo de nuevo, pero con un método diferente
resp, err := client.BuildSignAndSubmitTransaction(alice, aptos.TransactionPayload{
Payload: &aptos.EntryFunction{
Module: aptos.ModuleId{
Address: aptos.AccountOne,
Name: "aptos_account",
},
Function: "transfer",
ArgTypes: []aptos.TypeTag{},
Args: [][]byte{
accountBytes,
amountBytes,
},
}},
)
if err != nil {
panic("Failed to sign transaction:" + err.Error())
}
_, err = client.WaitForTransaction(resp.Hash)
if err != nil {
panic("Failed to wait for transaction:" + err.Error())
}
aliceBalance, err = client.AccountAPTBalance(alice.Address)
if err != nil {
panic("Failed to retrieve alice balance:" + err.Error())
}
bobBalance, err = client.AccountAPTBalance(bob.Address)
if err != nil {
panic("Failed to retrieve bob balance:" + err.Error())
}
fmt.Printf("\n=== Final Balances ===\n")
fmt.Printf("Alice: %d\n", aliceBalance)
fmt.Printf("Bob:%d\n", bobBalance)
}
func main() {
example(aptos.DevnetConfig)
}

Construir y enviar transacciones en la cadena implica los siguientes 5 pasos:

  1. Construir la transacción.
  2. Simular el costo. (Opcional)
  3. Firmar la transacción (si los costos simulados parecen razonables).
  4. Enviar la transacción a la red.
  5. Esperar para que la cadena valide y actualice.

Explorar Características Avanzadas de Transacciones

Sección titulada «Explorar Características Avanzadas de Transacciones»

Las transacciones tienen un par de características adicionales que les permiten adaptarse a tus necesidades, que puedes aprender aquí:

  1. Firmas Multi-Agente - Permitir el uso de múltiples cuentas para una sola transacción.
  2. Transacciones Patrocinadas - Hacer que otra cuenta pague las comisiones de gas por esta transacción.
  3. Envío de Transacciones por Lote - Cómo enviar múltiples transacciones rápidamente desde una sola cuenta.
  4. Serialización Canónica Binaria (BCS) - El formato utilizado para serializar datos para transacciones de Aptos.