Ir al contenido

Transacciones de Script

Ademas de llamar funciones entry publicadas, puedes enviar scripts Move compilados como transacciones. Los scripts son piezas independientes de bytecode Move que se ejecutan una vez y no se almacenan on-chain. Ofrecen mas flexibilidad que las llamadas a funciones entry porque un script puede invocar multiples funciones publicas, usar logica arbitraria y trabajar con tipos de diferentes modulos, todo dentro de una sola transaccion.

AspectoFunciones EntryScripts
DespliegueDeben publicarse como parte de un modulo Move on-chainNo se despliegan; el bytecode se incluye directamente en la transaccion
ReutilizacionInvocables por cualquier transaccion que referencie el moduloDe un solo uso; deben incluirse en cada transaccion
FlexibilidadLimitadas a la firma y logica definidas por la funcionPueden llamar multiples funciones publicas, usar condicionales y componer logica libremente
CompilacionCompiladas y publicadas con el moduloCompiladas por separado usando el CLI de Aptos
Casos de usoOperaciones estandar (transferencias, staking, interacciones con modulos)Operaciones complejas de un solo uso, llamadas por lotes, migraciones

Antes de poder enviar una transaccion de script, necesitas compilar el codigo fuente Move en bytecode. Usa el CLI de Aptos para compilar tu script.

  1. Escribe tu script Move.

    Crea un archivo llamado my_script.move con la siguiente estructura:

    script {
    use std::signer;
    use aptos_framework::aptos_account;
    use aptos_framework::coin;
    use aptos_framework::aptos_coin::AptosCoin;
    fun main(sender: &signer, recipient: address, amount: u64) {
    // Transfer APT from sender to recipient
    aptos_account::transfer(sender, recipient, amount);
    // Check the sender's remaining balance
    let _balance = coin::balance<AptosCoin>(signer::address_of(sender));
    }
    }
  2. Compila el script usando el CLI de Aptos.

    Ventana de terminal
    aptos move compile --named-addresses std=0x1,aptos_framework=0x1

    Esto produce un archivo de bytecode compilado (.mv) en el directorio build/. Incluiras este bytecode en el payload de tu transaccion de script.

Una vez que tienes el bytecode compilado, usa la variante TransactionPayload::Script para construir y enviar la transaccion.

  1. Cargar el bytecode del script compilado.

    Lee el archivo .mv producido por el compilador en un vector de bytes.

    let script_bytes = std::fs::read("build/my_script/bytecode_scripts/main.mv")?;
  2. Construir el payload del script.

    Construye un TransactionPayload::Script con el bytecode, argumentos de tipo y argumentos del script.

    use aptos_sdk::types::{TransactionPayload, ScriptPayload, ScriptArgument};
    let script_payload = TransactionPayload::Script(ScriptPayload::new(
    script_bytes,
    vec![], // Type arguments (empty if the script has no type parameters)
    vec![
    ScriptArgument::Address(bob.address()),
    ScriptArgument::U64(10_000_000),
    ],
    ));
  3. Construir, firmar y enviar usando el flujo de transaccion estandar.

    use aptos_sdk::transaction_builder::TransactionBuilder;
    let raw_txn = TransactionBuilder::new_with_payload(
    script_payload,
    aptos.get_chain_id().await?,
    )
    .sender(alice.address())
    .sequence_number(aptos.get_sequence_number(alice.address()).await?)
    .max_gas_amount(10_000)
    .gas_unit_price(100)
    .expiration_timestamp_secs(
    aptos.get_latest_ledger_info().await?.timestamp() + 60,
    )
    .build();
    let signed_txn = aptos.sign_transaction(&alice, raw_txn)?;
    let result = aptos.submit_and_wait(signed_txn).await?;
    let success = result
    .data
    .get("success")
    .and_then(|v| v.as_bool())
    .unwrap_or(false);
    println!("Script transaction success: {}", success);

Considera usar scripts en lugar de llamadas a funciones entry cuando:

  • Necesitas llamar multiples funciones de diferentes modulos en una sola transaccion atomica.
  • Necesitas usar valores de retorno de una llamada a funcion como entrada a otra dentro de la misma transaccion.
  • Estas realizando una operacion de un solo uso (como una migracion de datos o un airdrop) que no justifica desplegar un nuevo modulo.
  • Necesitas invocar una funcion public que no esta marcada como entry, la cual no puede ser llamada directamente mediante payloads de funciones entry.
/// This example demonstrates how to submit a compiled Move script as
/// a transaction using the Aptos Rust SDK.
use aptos_sdk::{Aptos, AptosConfig};
use aptos_sdk::account::Ed25519Account;
use aptos_sdk::types::{TransactionPayload, ScriptPayload, ScriptArgument};
use aptos_sdk::transaction_builder::TransactionBuilder;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Connect to testnet
let aptos = Aptos::new(AptosConfig::testnet())?;
// Generate and fund accounts
let alice = Ed25519Account::generate();
let bob = Ed25519Account::generate();
aptos.fund_account(alice.address(), 100_000_000).await?;
aptos.fund_account(bob.address(), 100_000_000).await?;
println!("Alice: {}", alice.address());
println!("Bob: {}", bob.address());
// Load compiled script bytecode
// Replace this path with the actual path to your compiled .mv file
let script_bytes = std::fs::read("build/my_script/bytecode_scripts/main.mv")?;
// Build the script payload
let script_payload = TransactionPayload::Script(ScriptPayload::new(
script_bytes,
vec![],
vec![
ScriptArgument::Address(bob.address()),
ScriptArgument::U64(10_000_000),
],
));
// Build the raw transaction
let raw_txn = TransactionBuilder::new_with_payload(
script_payload,
aptos.get_chain_id().await?,
)
.sender(alice.address())
.sequence_number(aptos.get_sequence_number(alice.address()).await?)
.max_gas_amount(10_000)
.gas_unit_price(100)
.expiration_timestamp_secs(
aptos.get_latest_ledger_info().await?.timestamp() + 60,
)
.build();
// Sign and submit
let signed_txn = aptos.sign_transaction(&alice, raw_txn)?;
let result = aptos.submit_and_wait(signed_txn).await?;
let success = result
.data
.get("success")
.and_then(|v| v.as_bool())
.unwrap_or(false);
println!("\nScript transaction success: {}", success);
// Verify balances
println!("\n=== Final Balances ===");
println!("Alice: {} octas", aptos.get_balance(alice.address()).await?);
println!("Bob: {} octas", aptos.get_balance(bob.address()).await?);
Ok(())
}