How do I execute a Move script on Aptos using the Rust SDK?

531 views Asked by At

I want to execute this Move script, e.g. at sources/top_up.move:

script {
    use std::signer;
    use aptos_framework::aptos_account;
    use aptos_framework::aptos_coin;
    use aptos_framework::coin;

    fun main(src: &signer, dest: address, desired_balance: u64) {
        let src_addr = signer::address_of(src);

        let balance = coin::balance<aptos_coin::AptosCoin>(src_addr);
        if (balance < desired_balance) {
            aptos_account::transfer(src, dest, desired_balance - balance);
        };
    }
}

This is calling functions on the aptos_coin.move module, which is deployed on chain. What it does isn't so important for this question, but in short, it checks that the balance of the destination account is less than desired_balance, and if so, tops it up to desired_balance.

I can execute this Move script via the CLI easily like this:

aptos move compile
aptos move run-script --compiled-script-path build/MyModule/bytecode_scripts/main.mv

Or even just this:

aptos move run-script --script-path sources/top_up.move

What I want to know is whether I can do this using the Rust SDK?

1

There are 1 answers

0
Daniel Porteous On BEST ANSWER

First, you need to compile the script, as you did above. Imagine you have a project layout like this:

src/
    main.rs
move/
    Move.toml
    sources/
        top_up.mv

You would want to go in to move/ and run aptos move compile, like you said above. From there, you can depend on the compiled script in your code (see below).

With that complete, here is a minimal code example demonstrating how to execute a Move script using the Rust SDK.

Cargo.toml:

[package]
name = "my-example"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1"
aptos-sdk = { git = "https://github.com/aptos-labs/aptos-core", branch = "mainnet" }

src/main.rs:

use aptos_sdk::crypto::ed25519::Ed25519PublicKey;
use aptos_sdk::types::transaction::authenticator::AuthenticationKey;
use aptos_sdk::{
    rest_client::Client,
    transaction_builder::TransactionFactory,
    types::{
        account_address::AccountAddress,
        chain_id::ChainId,
        transaction::{Script, SignedTransaction, TransactionArgument},
        LocalAccount,
    },
};

static SCRIPT: &[u8] =
    include_bytes!("../../move/build/MyModule/bytecode_scripts/main.mv");

fn main() -> anyhow::Result<()> {
    // Prior to the follow code we assume you've already acquired the necessary
    // information such as chain_id, the private key of the account submitting
    // the transaction, arguments for the Move script, etc.

    // Build a transaction factory.
    let txn_factory = TransactionFactory::new(chain_id);

    // Build a local representation of an account.
    let account = LocalAccount::new(
        AuthenticationKey::ed25519(&Ed25519PublicKey::from(&private_key)).derived_address()
        private_key,
        0,
    );

    // Build an API client.
    let client = Client::new("https://fullnode.mainnet.aptoslabs.com");

    // Create a builder where the payload is the script.
    let txn_builder = transaction_factory.script(Script::new(
        SCRIPT.to_vec(),
        // type args
        vec![],
        // args
        vec![
            TransactionArgument::Address(dest_address),
            TransactionArgument::U64(desired_balance),
        ],
    )));

    // Build the transaction request and sign it.
    let signed_txn = account.sign_with_transaction_builder(
        txn_builder
    );

    // Submit the transaction.
    client.submit_and_wait_bcs(&signed_transaction).await?;
}