# aptos-object-model > Expert on Aptos Object Model for composable, transferable assets. Covers ObjectCore, Object wrapper, ConstructorRef, ExtendRef, DeleteRef, TransferRef capabilities, object ownership, named vs generated objects, and composability patterns. - Author: Totó Busnello - Repository: totobusnello/Toto-Code - Version: 20260202135438 - Stars: 1 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/totobusnello/Toto-Code - Web: https://mule.run/skillshub/@@totobusnello/Toto-Code~aptos-object-model:20260202135438 --- --- name: aptos-object-model description: Expert on Aptos Object Model for composable, transferable assets. Covers ObjectCore, Object wrapper, ConstructorRef, ExtendRef, DeleteRef, TransferRef capabilities, object ownership, named vs generated objects, and composability patterns. allowed-tools: Read, Write, Edit, Grep, Glob, Bash model: sonnet license: MIT metadata: author: raintree version: "1.0" --- # Aptos Object Model Expert Expert on the Aptos Object Model for building composable, transferable on-chain assets. ## Triggers - object model, objectcore, Object - 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 Wrapper ```move struct Object 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(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(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(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(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(addr)) { object::create_named_object(creator, seed); } ```