aptos-object-model

$npx mdskill add eric861129/SKILLS_All-in-one/aptos-object-model

Create and manage composable on-chain assets using Aptos Object Model.

  • Enables building transferable, composable NFTs and assets on Aptos.
  • Uses Aptos Move ObjectCore, ConstructorRef, and TransferRef capabilities.
  • Recommends patterns based on asset lifecycle and ownership requirements.
  • Provides Move code examples for object creation, extension, and deletion.

SKILL.md

.github/skills/aptos-object-modelView on GitHub ↗
---
name: aptos-object-model
description: "Expert on Aptos Object Model for composable, transferable on-chain assets. Use when working with ObjectCore, Object wrappers, ConstructorRef, ExtendRef, DeleteRef, TransferRef capabilities, or implementing composable asset patterns on Aptos blockchain."
user-invocable: true
triggers:
  - Aptos object model
  - ObjectCore Move
  - ConstructorRef Aptos
  - implement composable asset Aptos
  - Object<T> Move pattern
  - TransferRef Aptos
  - named vs generated objects Aptos
  - composable NFT Aptos
---

# Aptos Object Model Expert

Expert on the Aptos Object Model for building composable, transferable on-chain assets.

## Triggers

- object model, objectcore, Object<T>
- constructorref, extendref, deleteref, transferref
- named object, generated object
- object ownership, composable object
- soul-bound, nesting

## Core Concepts

The Object Model enables:
- **Transferable resources** - Objects can move between accounts
- **Composability** - Objects can own other objects
- **Lifecycle management** - Create, extend, delete via refs
- **Ownership separation** - Owner address != object address

## ObjectCore

Every object has an `ObjectCore`:

```move
struct ObjectCore has key {
    owner: address,
    allow_ungated_transfer: bool,
}
```

## Object<T> Wrapper

```move
struct Object<phantom T> has copy, drop, store {
    inner: address  // Pointer to object
}
```

## Object Creation

### Named Objects (Deterministic)

```move
let constructor_ref = object::create_named_object(creator, b"SEED");
// Address = hash(creator_address, seed)
```

### Generated Objects (Random)

```move
let constructor_ref = object::create_object(creator);
// Non-deterministic address
```

### Sticky Objects (Cannot Delete)

```move
let constructor_ref = object::create_sticky_object(creator);
```

## References (Capabilities)

### ConstructorRef - Master Key (Creation Only)

```move
let constructor_ref = object::create_object(creator);

// Generate all other refs during creation
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);
let object_signer = object::generate_signer(&constructor_ref);

// Store refs at object address
move_to(&object_signer, Refs { extend_ref, transfer_ref, delete_ref });
```

### ExtendRef - Access Later

```move
// Get signer after creation
let object_signer = object::generate_signer_for_extending(&refs.extend_ref);
```

### TransferRef - Control Transfers

```move
// Disable transfers (soul-bound)
object::disable_ungated_transfer(&refs.transfer_ref);

// Enable transfers
object::enable_ungated_transfer(&refs.transfer_ref);

// Force transfer
object::transfer_with_ref(&refs.transfer_ref, new_owner);
```

### DeleteRef - Destroy Objects

```move
// Remove all resources first, then delete
let MyResource { value: _ } = move_from<MyResource>(object_addr);
object::delete(delete_ref);
```

## Ownership & Transfer

```move
// Get object info
let object_addr = object::object_address(&obj);
let owner = object::owner(obj);
let transferable = object::ungated_transfer_allowed(obj);

// User transfer (if allowed)
object::transfer(owner, obj, new_owner);
```

## Common Patterns

### Soul-Bound Token

```move
public fun create_sbt(creator: &signer, recipient: address) {
    let constructor_ref = token::create_named_token(...);
    
    let transfer_ref = object::generate_transfer_ref(&constructor_ref);
    object::disable_ungated_transfer(&transfer_ref);
    
    // One-time transfer to recipient
    let linear_ref = object::generate_linear_transfer_ref(&transfer_ref);
    object::transfer_with_ref(linear_ref, recipient);
    
    // Don't store transfer_ref - permanently non-transferable
}
```

### Composable NFT (Nesting)

```move
// Create parent
let parent_ref = token::create_named_token(...);
let parent_addr = object::address_from_constructor_ref(&parent_ref);

// Create child owned by parent
let child_ref = token::create_named_token(...);
let transfer_ref = object::generate_transfer_ref(&child_ref);
let linear_ref = object::generate_linear_transfer_ref(&transfer_ref);
object::transfer_with_ref(linear_ref, parent_addr);
```

### Singleton/Registry

```move
public fun get_or_create_registry(creator: &signer): address {
    let seed = b"REGISTRY";
    let addr = object::create_object_address(&signer::address_of(creator), seed);
    
    if (!object::object_exists<Registry>(addr)) {
        let ref = object::create_named_object(creator, seed);
        let signer = object::generate_signer(&ref);
        move_to(&signer, Registry { items: simple_map::create() });
    };
    
    addr
}
```

### Upgradeable Module Data

```move
struct DataRefs has key { extend_ref: ExtendRef }

public fun upgrade_config(new_config: Config) acquires DataRefs {
    let refs = borrow_global<DataRefs>(data_addr);
    let signer = object::generate_signer_for_extending(&refs.extend_ref);
    // Modify resources at data_addr
}
```

## Best Practices

- Store refs at object address, not creator address
- Generate all needed refs during creation (ConstructorRef is ephemeral)
- Use named objects for singletons, generated for collections
- Disable ungated transfer for soul-bound tokens
- Clean up all resources before deletion
- Document object ownership hierarchy

## Common Errors

### "Object does not exist"
```move
assert!(object::object_exists<T>(addr), ERROR);
```

### "Ungated transfer not allowed"
```move
// Use TransferRef for forced transfer
object::transfer_with_ref(&refs.transfer_ref, recipient);
```

### "Object already exists"
```move
// Check existence before creating named object
if (!object::object_exists<ObjectCore>(addr)) {
    object::create_named_object(creator, seed);
}
```

More from eric861129/SKILLS_All-in-one

SkillDescription
agnixUse when user asks to 'lint agent configs', 'validate skills', 'check CLAUDE.md', 'validate hooks', 'lint MCP'. Validates agent configuration files against 231 rules across 10+ AI tools.
anthropic-expertExpert on Anthropic Claude API, models, prompt engineering, function calling, vision, and best practices. Triggers on anthropic, claude, api, prompt, function calling, vision, messages api, embeddings
aptos-cliExpert in Aptos CLI for account management, contract deployment, transaction submission, and node operations. Use when using the Aptos CLI to initialize profiles, deploy Move contracts, submit transactions, manage accounts, or operate Aptos nodes.
aptos-coreExpert in Aptos blockchain core architecture: consensus (AptosBFT), execution (Block-STM), and networking. Use when analyzing Aptos protocol design, the Rust codebase, validator operations, or understanding how Block-STM parallel execution works.
aptos-dapp-integrationExpert on building Aptos dApps with frontend integration. Covers wallet connectivity (Petra, Martian, Pontem), wallet adapter patterns, TypeScript SDK, transaction building and submission, account management, and React/Next.js integration.
aptos-frameworkExpert on Aptos Framework (0x1 standard library) modules including account, coin, fungible_asset, object, timestamp, table, smart_table, event, randomness, aggregator, and resource_account. Essential for all Aptos development.
aptos-gas-optimizationAptos gas optimization expert for Move smart contracts. Covers storage costs, execution efficiency, inline functions, aggregators for parallel execution, Table vs SmartTable vs vector tradeoffs, event optimization, struct packing, and gas profiling tools.
aptos-indexerExpert in Aptos Indexer architecture and GraphQL API for querying blockchain data. Use when querying NFTs, coin balances, or transaction history via GraphQL, designing custom processors, or optimizing data retrieval from the Aptos blockchain.
aptos-move-languageExpert on Move programming language fundamentals including abilities (copy/drop/store/key), generics, phantom types, references, global storage operations (move_to/move_from/borrow_global), signer pattern, visibility modifiers, and advanced type system features.
aptos-move-testingExpert on testing Move smart contracts including unit tests, integration tests, Move Prover formal verification, debugging strategies, test coverage, and CI/CD integration for Aptos development.