Skip to content

Modules on Aptos

Aptos allows for permissionless publishing of modules within a package as well as upgrading those that have appropriate compatibility policy set.

A module contains several structs and functions, much like Rust.

During package publishing time, a few constraints are maintained:

  • Both Structs and public function signatures are published as immutable.

Historically, module initialization was handled by an init_module function:

  • When a module was published for the first time (i.e., the module did not exist on-chain), the VM would search for and execute the init_module(account: &signer) function.
  • When upgrading an existing on-chain module, init_module is NOT called.
  • The signer of the publishing account was passed in. The function had to be private, take at most one &signer parameter, have no generic parameters, and return no value.

Because this implicit publish-time execution is being removed, new modules should use the explicit pattern below instead.

Recommended: explicit initialize entry function

Section titled “Recommended: explicit initialize entry function”

Expose an entry fun initialize that the module publisher calls in a separate transaction after publishing the package. Guard it so it runs only once, and only for the publisher:

module my_addr::my_module {
use std::signer;
use aptos_framework::error;
/// Caller is not the module publisher.
const ENOT_AUTHORIZED: u64 = 1;
/// Module is already initialized.
const EALREADY_INITIALIZED: u64 = 2;
struct ModuleData has key { /* fields */ }
entry fun initialize(publisher: &signer) {
assert!(signer::address_of(publisher) == @my_addr, error::permission_denied(ENOT_AUTHORIZED));
assert!(!exists<ModuleData>(@my_addr), error::already_exists(EALREADY_INITIALIZED));
move_to(publisher, ModuleData { /* ... */ });
}
}