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.
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.
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:
Copy
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 a config.yaml file inside it. In config.yaml, you will find your project setup.
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:
Copy
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 ); }}
Publish your compiled and tested Move module by running:
Copy
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:
Copy
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.