Aptos: Publish a module to save and retrieve a message on-chain
Aptos uses its own terminology for widely-known Web3 entities. Smart contracts are called Modules and are written in the Move language. Modules are also not deployed but published on the Aptos chain.
The objective of this tutorial is to familiarize you with the Aptos network, the Move language and modules written in it. In the end of this tutorial, you will be able to publish, test, and interact with Move modules in Aptos.
Specifically, in this tutorial, you will:
- Initialize an Aptos project using the Aptos CLI.
- Publish a module on the Aptos testnet.
- Interact with the module to save a message.
- Use the Aptos REST API to retrieve the message.
Prerequisites
- Chainstack account to deploy an Aptos node.
- Martian Aptos wallet to receive testnet Aptos token (APT).
- Aptos CLI to compile, publish, and interact with the Move module.
Overview
To get from zero to publishing your string via the module to Aptos testnet, do the following:
- With Chainstack, create a public chain project.
- With Chainstack, join Aptos testnet.
- With Chainstack, access your Aptos node credentials.
- Set up your Martian wallet to work through the Chainstack Aptos node.
- Fund your account through the Aptos testnet faucet.
- Install the Aptos CLI.
- Create a Move project.
- Create and configure your Aptos project.
- Create a module in the Move language.
- Compile and test the Move module.
- Publish the Move module.
- Save and retrieve a message on the Aptos chain.
Step-by-step
Create a public chain project
See Create a project.
Join the Aptos testnet
Get node access and credentials
See View node access and credentials.
Set up Martian wallet
See Aptos tooling: Martian wallet.
Fund your account
Your account needs to pay fees in testnet APT to publish the module and interact with it. Fund your account with the Aptos testnet faucet.
Install the Aptos CLI
You need the Aptos CLI to interact with your Move module. Set up the Aptos CLI.
Create a Move project
-
In your project directory, create a Move project:
aptos move init --name save-message
where
save-message
— name of the package.This creates a
sources
directory and aMove.toml
file. -
Open your
Move.toml
file and edit it to add[addresses]
and[dev-addresses]
, where:dev = "_"
— your default Aptos account.dev = "0xC0FFEE"
— an alternative Aptos account for tests.
Example:
[package] name = 'save-message' version = '1.0.0' [addresses] dev = "_" [dev-addresses] dev = "0xC0FFEE" [dependencies.AptosFramework] git = 'https://github.com/aptos-labs/aptos-core.git' rev = 'main' subdir = 'aptos-move/framework/aptos-framework'
Packages naming
Note that packages have one-time names. If you want to re-publish the package, you must change its name.
Create and configure an Aptos project
-
In your project directory, run
aptos init > custom
. This will start a configuration process, during which you need to set up your Chainstack endpoint and Martian wallet private key. Adding the private key will retrieve your Aptos public address automatically. -
Add your Aptos node endpoint deployed with Chainstack.
-
At the faucet URL request, type
skip
since you have already funded your account on the previous step. -
Paste your Martian wallet private key to finish configuring your project. The key is used to send transactions and retrieve your public address. Example of a successful result:
Aptos CLI is now set up for account ...4474 as profile default! Run `aptos --help` for more information about commands { "Result": "Success" }
As a result, you get a
.aptos
directory with aconfig.yaml
file inside it. Inconfig.yaml
, you will find your project setup.
Create a Move module
In your Move project directory, navigate to the sources
directory. Create your Move module file message.move
which allows you to call the set_message
function and save a string on-chain:
module dev::message {
use std::error;
use std::signer;
use std::string;
use aptos_framework::account;
use aptos_framework::event;
//:!:>resource
struct MessageHolder has key {
message: string::String,
message_change_events: event::EventHandle<MessageChangeEvent>,
}
//<:!:resource
struct MessageChangeEvent has drop, store {
from_message: string::String,
to_message: string::String,
}
/// There is no message present
const ENO_MESSAGE: u64 = 0;
public fun get_message(addr: address): string::String acquires MessageHolder {
assert!(exists<MessageHolder>(addr), error::not_found(ENO_MESSAGE));
*&borrow_global<MessageHolder>(addr).message
}
public entry fun set_message(account: signer, message: string::String)
acquires MessageHolder {
let account_addr = signer::address_of(&account);
if (!exists<MessageHolder>(account_addr)) {
move_to(&account, MessageHolder {
message,
message_change_events: account::new_event_handle<MessageChangeEvent>(&account),
})
} else {
let old_message_holder = borrow_global_mut<MessageHolder>(account_addr);
let from_message = *&old_message_holder.message;
event::emit_event(&mut old_message_holder.message_change_events, MessageChangeEvent {
from_message,
to_message: copy message,
});
old_message_holder.message = message;
}
}
#[test(account = @0x1)]
public entry fun sender_can_set_message(account: signer) acquires MessageHolder {
let addr = signer::address_of(&account);
aptos_framework::account::create_account_for_test(addr);
set_message(account, string::utf8(b"Hello Chainstack dev"));
assert!(
get_message(addr) == string::utf8(b"Hello Chainstack dev"),
ENO_MESSAGE
);
}
}
Compile and test the Move module
-
To compile your Move module, run:
aptos move compile --named-addresses dev=default
-
After the module compiled, run a build-in test which checks if the
set_message
andget_message
functions work:aptos move test
Publish the Move module
-
Publish your compiled and tested Move module by running:
aptos move publish --named-addresses dev=default
-
Type
yes
to confirm publishing the transaction on the Aptos chain.The module will publish and the terminal will return the module information. You can use the transaction hash to retrieve transaction details. To do so, run:
curl --location --request GET 'YOUR_CHAINSTACK_ENDPOINT/v1/transactions/by_hash/0x815cecb01a962331ca34904653a26715e6cd8e631d2d1b7da17b593adda1ea65' \ --header 'Content-Type: application/json'
where YOUR_CHAINSTACK_ENDPOINT is your Aptos node endpoint you used earlier.
Save and retrieve a message on the Aptos chain
-
To save a message on the Aptos chain, run:
aptos move run --function-id 'default::message::set_message' --args 'string:Hello Chainstack dev'
where:
run
— a Move command to call functionsfunction-id
— a function to callargs
— arguments of the function
-
Type
yes
to confirm publishing the transaction on the Aptos chain. -
Retrieve the published message via the REST API by running:
curl --location --request GET 'YOUR_CHAINSTACK_ENDPOINT/v1/accounts/c0e0ce57eaf9680ae67252fb3126f25aa86bb098b05f7b72cf0cf0de57c72a7f/resource/0xc0e0ce57eaf9680ae67252fb3126f25aa86bb098b05f7b72cf0cf0de57c72a7f::message::MessageHolder' \ --header 'Content-Type: application/json'
where YOUR_CHAINSTACK_ENDPOINT is your Aptos node endpoint you used earlier.
Successful response example:
{
"type": "0xc0e0ce57eaf9680ae67252fb3126f25aa86bb098b05f7b72cf0cf0de57c72a7f::message::MessageHolder",
"data": {
"message": "Hello Chainstack dev",
"message_change_events": {
"counter": "0",
"guid": {
"id": {
"addr": "0xc0e0ce57eaf9680ae67252fb3126f25aa86bb098b05f7b72cf0cf0de57c72a7f",
"creation_num": "4"
}
}
}
}
}
Conclusion
This tutorial guided you through the basics of creating, publishing, and testing a simple module that saves a string on the Aptos chain.
About the author
Updated 12 months ago