Description
Move development on Aptos
SKILL.md
Move Language
Move on Aptos is a safe, resource-oriented programming language for smart contracts on the Aptos blockchain. It uses a linear type system to enforce ownership and prevent double-spending at compile time.
Move Language Basics
- Modules are the unit of code organization, published at an address.
- Structs define data types; abilities (
key,store,copy,drop) control what operations are permitted. - Entry functions (
entry fun) are transaction entry points callable from outside Move. - View functions (
#[view]) are read-only queries that do not modify state. - Global storage stores resources (structs with
key) at addresses. - Move 2 syntax (required):
- Read resource:
&T[addr](notborrow_global<T>(addr)) - Mutate resource:
&mut T[addr](notborrow_global_mut<T>(addr)) - Access field:
T[addr].fielddirectly (the compiler inserts the ref op) acquiresannotations are no longer needed — do not add them.
- Read resource:
- Error codes: Use named constants for abort codes (
const E_NOT_FOUND: u64 = 1;) and document them. - Comments: Use
//for regular comments.///is a doc comment and is only valid directly before amodule,struct,enum,fun, orconstdeclaration. - Edit hook: The edit hook auto-runs on
.movefiles after edits. If it reports compilation errors, fix them before proceeding with further changes.
Links
Move Specification Language
Move specifications use spec blocks to express formal properties that are checked
by the Move Prover.
Function spec clauses
These appear in spec fun_name { ... } blocks. Spec blocks always appear after the function
definition. If fun_name clashes with a soft keyword (e.g. lemma), use spec @fun_name { ... }
to escape it.
ensures <expr>: Postcondition that must hold when the function returns normally. Evaluated in the post-state. Useold(expr)to refer to pre-state values.aborts_if <expr>: Condition under which the function may abort. Evaluated in the pre-state — do not useold()(seeold()usage rules below). If anyaborts_ifconditions are present, the function must abort if and only if one of the conditions holds. Omitting allaborts_ifclauses means abort behavior is unspecified (any abort is allowed). To express that a function never aborts, writeaborts_if false;.requires <expr>: Precondition that callers must satisfy. Evaluated in the pre-state — Do not useold()(seeold()usage rules below).modifies <resource>: Declares which global resources the function may modify.
Loop invariants
Loop invariants appear in a spec block after the loop body:
while (cond) {
// body
} spec {
invariant <expr>;
};
invariant <expr>: A property that holds before the first iteration and is preserved by each iteration.old(x)is only allowed on function parameters (seeold()usage rules below.)
Loops without invariants cause the prover to havoc all loop-modified variables, which can
produce vacuous, incorrect, or overly weak specifications. Every loop needs an invariant —
examine the actual while loops in function bodies to find all loops that lack one.
A good invariant:
- Holds before the first iteration (initial values satisfy it).
- Is preserved by each iteration (inductive step).
- Relates loop-modified variables to function parameters and constants
(e.g., bounds like
i <= n, accumulators likesum == i * step).
Expressions in specs
old(expr): Value ofexprat function entry. Seeold()usage rules below for where this is allowed.result: Return value. Only valid inensures.global<T>(addr): Global resource of typeTat addressaddr.exists<T>(addr): True if a resource of typeTexists at addressaddr.- Numeric type bounds:
MAX_U8,MAX_U16,MAX_U32,MAX_U64,MAX_U128,MAX_U256. - No dereference or borrow:
*eand&eare not allowed in spec expressions. Spec expressions operate on values, not references — access fields directly (e.g.v.field, not(*v).fieldor(&v).field).
old() usage rules
old(expr) means "value of expr at function entry." It is only valid in specific contexts:
Wrong / Right examples:
// WRONG: old() in aborts_if — compilation error
aborts_if old(x) + old(y) > MAX_U64;
// RIGHT: aborts_if is pre-state, just use the variables directly
aborts_if x + y > MAX_U64;
// WRONG: old() in requires — compilation error
requires old(len(v)) > 0;
// RIGHT: requires is pre-state
requires len(v) > 0;
// WRONG: old(local) in loop invariant — compilation error
invariant old(sum) <= old(n) * MAX_U64;
// RIGHT: sum is a local — use it directly; n is a parameter — old(n) is ok
invariant sum <= old(n) * MAX_U64;
// WRONG: old(resource) in loop invariant — compilation error
invariant old(global<T>(addr)).field == 0;
// RIGHT: use resource directly
invariant global<T>(addr).field == 0;
Referring to Behavior of other Functions
When specifying a function that calls other functions which are not inline functions, you can use behavioral predicates to abstract the callee's specification without inlining its details. These built-in predicates lift a function's spec clauses into expressions:
requires_of<f>(args)— true whenf'srequiresclauses hold forargs.aborts_of<f>(args)— true whenf'saborts_ifclauses hold forargs.ensures_of<f>(args, result)— true whenf'sensuresclauses hold forargsand the givenresultvalue(s). For functions returning unit, omit the result argument. For multiple return values, passresult_1, result_2, ....result_of<f>(args)— the return value offwhen called withargs, usable inletbindings and expressions inside spec blocks.
The <f> target can be:
- A function parameter of function type:
ensures_of<f>(x, result)wherefis a parameter with type|u64| u64. - A named function (same module or cross-module):
ensures_of<increment>(x, result)orensures_of<M::increment>(x, result). - A generic function with explicit or inferred type arguments:
ensures_of<identity<u64>>(x, result)orensures_of<identity>(x, result).
Examples:
Specifying a higher-order function that applies a callback:
fun apply(f: |u64| u64, x: u64): u64 { f(x) }
spec apply {
aborts_if aborts_of<f>(x);
ensures ensures_of<f>(x, result);
}
Using result_of to chain calls in a spec (e.g. f(f(x))):
fun apply_seq(f: |u64| u64 has copy, x: u64): u64 { f(f(x)) }
spec apply_seq {
let y = result_of<f>(x);
requires requires_of<f>(x) && requires_of<f>(y);
aborts_if aborts_of<f>(x) || aborts_of<f>(y);
ensures result == result_of<f>(y);
}
Referring to a named function's behavior from a caller:
spec bar {
ensures ensures_of<increment>(x, result);
}
Using result_of inside loop invariants with closures:
spec {
invariant forall j in 0..i: !result_of<pred>(v[j]);
};
Property markers
The [inferred] property marks conditions that were not written by the user. Its value indicates
the origin or quality:
[inferred]: Automatically inferred by weakest-precondition (WP) analysis. It may be overly complex, redundant, or occasionally incorrect.[inferred = vacuous]: Inferred by WP but detected as potentially vacuous (trivially true) due to unconstrained quantifier variables. Typically results from missing loop invariants.[inferred = sathard]: Inferred by WP but contains quantifier patterns that are hard for SMT solvers. Likely to cause verification timeouts — should be simplified or reformulated.
Links
Move Packages
A Move package is a directory with a Move.toml manifest and source files. The manifest defines the package name, dependencies, and named addresses.
Named Addresses
Modules are published at named addresses (e.g., @my_package). These must resolve to hex values for compilation.
[addresses]— production addresses (may use_placeholder for deploy-time assignment)[dev-addresses]— development/test values (used when compiling in dev or test mode)
Fixing "Unresolved addresses" errors: For each Named address 'X' in package 'Y', add X = "0x..." to [dev-addresses] in that package's Move.toml. Use 0x100 and up, avoiding reserved addresses (0x0=vm_reserved, 0x1=std/aptos_std/aptos_framework, 0x3=aptos_token, 0x4=aptos_token_objects, 0x5=aptos_trading, 0x7=aptos_experimental, 0xA=aptos_fungible_asset, 0xA550C18=core_resources):
[dev-addresses]
my_package = "0x100"
other_addr = "0x101"
Checking Move Code
Use the move_package_status MCP tool to check for compilation errors and warnings.
- Call
move_package_statuswithpackage_pathset to the package directory. - The tool sets error and returns detailed error messages if the package does not compile.
Notice that like with a build system, the tool is idempotent, and does not cause recompilation if the compilation result and sources are up-to-date.
Package Manifest
Use the move_package_manifest MCP tool to discover source files and dependencies
of a Move package:
- Call
move_package_manifestwithpackage_pathset to the package directory. - The result includes
source_paths(target modules) anddep_paths(dependencies).
Querying Package Structure
Use the move_package_query MCP tool to inspect the structure of a Move package.
Parameters:
package_path(required) — path to the Move package directory.query(required) — one of the query types below.function(required forfunction_usage) — function name in the formmodule_name::function_name.
Query Types
dep_graph— returns a map from each module to the modules it depends on. Useful for understanding module layering and import structure.module_summary— returns a summary of each module's constants, structs, and functions. Useful for getting an overview without reading all source files.call_graph— returns a function-level call graph as a map from each function to the functions it calls.function_usage— returns direct and transitive calls/uses for a given function. "called" = direct calls; "used" = direct calls + closure captures. Requires thefunctionparameter.
More skills from the aptos-ai repository
View all 7 skillsmove-check
check Move packages for compilation errors
Jul 19DebuggingWeb3move-inf
infer specifications for Move packages
Jul 19Data ModelingWeb3move-init
initialize Move workflow routing
Jul 19ConfigurationWeb3move-prove
verify Move specifications with Move Prover
Jul 19TestingWeb3move-replay
replay and debug Aptos transactions
Jul 19DebuggingWeb3move-test
generate unit tests for Move code
Jul 19TestingWeb3
More from Aptos Labs
View publisheranalyze-gas-optimization
optimize Aptos Move contracts for gas
aptos-agent-skills
Jul 12BlockchainPerformanceSmart Contractscreate-aptos-project
scaffold new Aptos dApp projects
aptos-agent-skills
Jul 12Next.jsTypeScriptViteWeb3deploy-contracts
deploy Move contracts to Aptos networks
aptos-agent-skills
Jul 12DeploymentEngineeringSmart Contractsgenerate-tests
generate test suites for Move contracts
aptos-agent-skills
Jul 12EngineeringQATestingmodernize-move
modernize Move V1 contracts to V2
aptos-agent-skills
Jul 12Code AnalysisEngineeringMigrationsearch-aptos-examples
search Aptos reference implementations
aptos-agent-skills
Jul 12BlockchainDocumentationSearch
