move-expert

Move language expert for Movement blockchain. Automatically triggered when working with .move files, discussing Move/Movement/Aptos concepts, debugging Move compiler errors, or building smart contracts.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "move-expert" with this command: npx skills add rahat-ch/move-plugin/rahat-ch-move-plugin-move-expert

Move Expert for Movement Blockchain

You are an expert Move developer specializing in Movement blockchain development. You help users write, debug, and deploy Move smart contracts.

Critical: Move Version Compatibility

Movement supports Move 2.1 ONLY. Do NOT use or suggest:

  • &mut Resource[addr] syntax (Move 2.2+)
  • #[randomness] attribute (Move 2.2+)
  • Any Move 2.2/2.3 features

Use these Move 2.1 patterns instead:

  • borrow_global_mut<Resource>(addr) for mutable borrows
  • External randomness via oracle or VRF

Movement Network Endpoints

Mainnet (Chain ID: 126)

  • RPC: https://mainnet.movementnetwork.xyz/v1
  • Explorer: https://explorer.movementnetwork.xyz/?network=mainnet

Bardock Testnet (Chain ID: 250)

  • RPC: https://testnet.movementnetwork.xyz/v1
  • Faucet: https://faucet.movementnetwork.xyz/
  • Explorer: https://explorer.movementnetwork.xyz/?network=bardock+testnet

Core Move Concepts

Module Structure

module my_addr::my_module {
    use std::signer;
    use aptos_framework::object;

    // Error codes (const)
    const E_NOT_OWNER: u64 = 1;

    // Resources (structs with abilities)
    struct MyResource has key, store {
        value: u64,
    }

    // Init function (called on publish)
    fun init_module(sender: &signer) {
        // Setup code
    }

    // Entry functions (callable from transactions)
    public entry fun do_something(sender: &signer) {
        // Implementation
    }

    // View functions (read-only, no gas)
    #[view]
    public fun get_value(addr: address): u64 acquires MyResource {
        borrow_global<MyResource>(addr).value
    }
}

Abilities

AbilityMeaning
keyCan be stored as top-level resource
storeCan be stored inside other structs
copyCan be copied (duplicated)
dropCan be discarded/destroyed

Common patterns:

  • has key - Top-level resource
  • has key, store - Resource that can also be nested
  • has store, drop, copy - Value type (like Token info)
  • has drop - Event structs

Global Storage Operations

// Store resource at signer's address
move_to(signer, resource);

// Check if resource exists
exists<MyResource>(addr);

// Borrow immutable reference
let ref = borrow_global<MyResource>(addr);

// Borrow mutable reference
let ref = borrow_global_mut<MyResource>(addr);

// Remove and return resource
let resource = move_from<MyResource>(addr);

Signer Operations

use std::signer;

// Get address from signer
let addr = signer::address_of(signer);

// Signer is proof of account ownership
// Cannot be forged or transferred

Object Model (Aptos Objects)

Objects are the modern way to create composable, transferable resources.

Creating Objects

use aptos_framework::object::{Self, Object, ConstructorRef};

// Create a named object (deterministic address)
let constructor_ref = object::create_named_object(
    creator,
    b"my_seed"
);

// Create a random object (unique address)
let constructor_ref = object::create_object(creator_addr);

// Create sticky object (non-deletable, at module address)
let constructor_ref = object::create_sticky_object(@my_addr);

// Get the object signer to store resources
let obj_signer = object::generate_signer(&constructor_ref);

// Store resource at object address
move_to(&obj_signer, MyData { value: 100 });

// Get object from constructor
let obj: Object<MyData> = object::object_from_constructor_ref(&constructor_ref);

Object References

// Generate refs from constructor (must be done at creation time)
let extend_ref = object::generate_extend_ref(&constructor_ref);
let transfer_ref = object::generate_transfer_ref(&constructor_ref);
let delete_ref = object::generate_delete_ref(&constructor_ref);

// Store refs for later use
struct MyController has key {
    extend_ref: ExtendRef,
    transfer_ref: TransferRef,
}

Working with Objects

// Get object address
let obj_addr = object::object_address(&obj);

// Check ownership
let is_owner = object::is_owner(obj, addr);
let owner = object::owner(obj);

// Transfer object
object::transfer(owner_signer, obj, recipient);

// Calculate deterministic address
let obj_addr = object::create_object_address(&creator, seed);

Fungible Assets (FA)

Modern token standard replacing legacy Coin module.

Creating a Fungible Asset

use aptos_framework::fungible_asset::{Self, MintRef, BurnRef, TransferRef, Metadata};
use aptos_framework::primary_fungible_store;
use aptos_framework::object;

struct FAController has key {
    mint_ref: MintRef,
    burn_ref: BurnRef,
    transfer_ref: TransferRef,
}

fun create_fa(creator: &signer) {
    // Create object to hold FA metadata
    let constructor_ref = object::create_sticky_object(@my_addr);

    // Initialize as fungible asset with primary store
    primary_fungible_store::create_primary_store_enabled_fungible_asset(
        &constructor_ref,
        option::some(1000000000), // max_supply (optional)
        string::utf8(b"My Token"),
        string::utf8(b"MTK"),
        8, // decimals
        string::utf8(b"https://example.com/icon.png"),
        string::utf8(b"https://example.com"),
    );

    // Generate refs for mint/burn/transfer control
    let mint_ref = fungible_asset::generate_mint_ref(&constructor_ref);
    let burn_ref = fungible_asset::generate_burn_ref(&constructor_ref);
    let transfer_ref = fungible_asset::generate_transfer_ref(&constructor_ref);

    // Store refs
    let obj_signer = object::generate_signer(&constructor_ref);
    move_to(&obj_signer, FAController { mint_ref, burn_ref, transfer_ref });
}

Minting Tokens

fun mint(recipient: address, amount: u64) acquires FAController {
    let controller = borrow_global<FAController>(@my_addr);
    let fa = fungible_asset::mint(&controller.mint_ref, amount);
    primary_fungible_store::deposit(recipient, fa);
}

Burning Tokens

fun burn(from: address, amount: u64) acquires FAController {
    let controller = borrow_global<FAController>(@my_addr);
    let fa = primary_fungible_store::withdraw(from_signer, metadata, amount);
    fungible_asset::burn(&controller.burn_ref, fa);
}

Checking Balance

#[view]
public fun balance(owner: address, metadata: Object<Metadata>): u64 {
    primary_fungible_store::balance(owner, metadata)
}

Transferring Tokens

// User-initiated transfer
public entry fun transfer(
    sender: &signer,
    metadata: Object<Metadata>,
    recipient: address,
    amount: u64
) {
    primary_fungible_store::transfer(sender, metadata, recipient, amount);
}

// Admin transfer (using transfer_ref)
fun admin_transfer(
    from: address,
    to: address,
    amount: u64
) acquires FAController {
    let controller = borrow_global<FAController>(@my_addr);
    let from_store = primary_fungible_store::ensure_primary_store_exists(from, metadata);
    let to_store = primary_fungible_store::ensure_primary_store_exists(to, metadata);
    fungible_asset::transfer_with_ref(
        &controller.transfer_ref,
        from_store,
        to_store,
        amount
    );
}

Token Objects (NFTs)

Modern NFT standard using objects.

Creating a Collection

use aptos_token_objects::collection;
use aptos_token_objects::token;

fun create_collection(creator: &signer) {
    collection::create_unlimited_collection(
        creator,
        string::utf8(b"My Collection Description"),
        string::utf8(b"My Collection"),
        option::none(), // royalty
        string::utf8(b"https://example.com/collection"),
    );
}

// Or with fixed supply
fun create_fixed_collection(creator: &signer) {
    collection::create_fixed_collection(
        creator,
        string::utf8(b"Description"),
        1000, // max_supply
        string::utf8(b"Collection Name"),
        option::none(),
        string::utf8(b"https://example.com"),
    );
}

Minting NFTs

fun mint_nft(creator: &signer, recipient: address) {
    let constructor_ref = token::create_named_token(
        creator,
        string::utf8(b"Collection Name"),
        string::utf8(b"Token description"),
        string::utf8(b"Token #1"),
        option::none(), // royalty
        string::utf8(b"https://example.com/token/1"),
    );

    // Transfer to recipient
    let transfer_ref = object::generate_transfer_ref(&constructor_ref);
    let token_obj = object::object_from_constructor_ref(&constructor_ref);
    object::transfer_with_ref(
        object::generate_linear_transfer_ref(&transfer_ref),
        recipient
    );
}

Token with Custom Data

struct MyTokenData has key {
    power: u64,
    rarity: String,
}

fun mint_with_data(creator: &signer) {
    let constructor_ref = token::create(
        creator,
        string::utf8(b"Collection"),
        string::utf8(b"Description"),
        string::utf8(b"Token Name"),
        option::none(),
        string::utf8(b"https://example.com/token"),
    );

    let token_signer = object::generate_signer(&constructor_ref);
    move_to(&token_signer, MyTokenData {
        power: 100,
        rarity: string::utf8(b"Legendary"),
    });
}

Events

use aptos_framework::event;

#[event]
struct TransferEvent has drop, store {
    from: address,
    to: address,
    amount: u64,
}

fun emit_transfer(from: address, to: address, amount: u64) {
    event::emit(TransferEvent { from, to, amount });
}

Common Patterns

Access Control

const E_NOT_ADMIN: u64 = 1;

struct AdminConfig has key {
    admin: address,
}

fun only_admin(sender: &signer) acquires AdminConfig {
    let config = borrow_global<AdminConfig>(@my_addr);
    assert!(
        signer::address_of(sender) == config.admin,
        E_NOT_ADMIN
    );
}

Pausable

const E_PAUSED: u64 = 2;

struct PauseState has key {
    paused: bool,
}

fun when_not_paused() acquires PauseState {
    let state = borrow_global<PauseState>(@my_addr);
    assert!(!state.paused, E_PAUSED);
}

Counter Pattern

struct Counter has key {
    value: u64,
}

fun increment() acquires Counter {
    let counter = borrow_global_mut<Counter>(@my_addr);
    counter.value = counter.value + 1;
}

Move.toml Configuration

[package]
name = "my_project"
version = "1.0.0"
authors = []

[addresses]
my_addr = "_"

[dependencies.AptosFramework]
git = "https://github.com/movementlabsxyz/aptos-core.git"
rev = "m1"
subdir = "aptos-move/framework/aptos-framework"

[dependencies.AptosStdlib]
git = "https://github.com/movementlabsxyz/aptos-core.git"
rev = "m1"
subdir = "aptos-move/framework/aptos-stdlib"

[dependencies.AptosTokenObjects]
git = "https://github.com/movementlabsxyz/aptos-core.git"
rev = "m1"
subdir = "aptos-move/framework/aptos-token-objects"

Common Compiler Errors & Fixes

Ability Errors

Error: "type does not have the 'key' ability"
Fix: Add `has key` to struct definition
Error: "cannot copy value"
Fix: Add `has copy` or use reference `&`
Error: "cannot drop value"
Fix: Add `has drop` or explicitly handle the value

Borrow Errors

Error: "cannot borrow global mutably"
Fix: Use `borrow_global_mut` and add `acquires` annotation
Error: "value still borrowed"
Fix: Ensure previous borrow ends before new borrow

Type Errors

Error: "expected type X, found Y"
Fix: Check function signatures, ensure types match
Error: "missing acquires annotation"
Fix: Add `acquires ResourceName` to function signature

Access Errors

Error: "function is not public"
Fix: Add `public` or `public entry` to function
Error: "module not found"
Fix: Check Move.toml dependencies, ensure correct import path

CLI Installation

Install the Movement CLI via Homebrew (macOS/Linux):

brew install movementlabsxyz/tap/movement
movement --version

Fallback: Aptos CLI v7.4.0 is supported if Movement CLI is unavailable:

brew install aptos
aptos --version  # must be exactly 7.4.0

Use the setup_cli MCP tool to check installation status, get install instructions, or initialize an account.

CLI Commands

Movement CLI is recommended. Aptos CLI v7.4.0 is supported as a fallback only.

# Compile
movement move compile

# Test
movement move test

# Publish
movement move publish --named-addresses my_addr=default

# Initialize account
movement init --network testnet

# Check account
movement account list

# Run script
movement move run --function-id 'my_addr::module::function'

Best Practices

  1. Use objects over legacy resources - More flexible, composable
  2. Use FA over Coin - Modern standard with better features
  3. Always check exists before borrow_global - Prevents abort
  4. Store refs at creation time - Can't generate refs later
  5. Use named objects for deterministic addresses - Easier to find
  6. Emit events for important state changes - Better indexability
  7. Use error codes with constants - Easier debugging
  8. Test with movement move test - Always test before deploy

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Web3

Binance Coach

AI-powered crypto trading behavior coach for Binance users. Analyzes live portfolio health, detects emotional trading patterns (FOMO, panic selling, overtrad...

Registry SourceRecently Updated
Web3

zHive

Register as a trading agent on zHive, post predictions on recurring megathread rounds for top 100 crypto tokens, and compete for accuracy rewards. Rounds res...

Registry SourceRecently Updated
5320kerlos
Web3

Edge.Trade

Use when user asks about crypto tokens, trading, portfolios, or price alerts.

Registry SourceRecently Updated
Web3

Hive Marketplace

Connect your AI agent to the Hive platform to find, accept, and complete real-world work requests including development, analysis, and research projects.

Registry SourceRecently Updated