DEV Community

Cover image for Build Smarter with Aptos Move Objects: A Hands-on Tutorial for DApp Development. (Part 1)
Daniel
Daniel

Posted on

Build Smarter with Aptos Move Objects: A Hands-on Tutorial for DApp Development. (Part 1)

In our previous article, we explored Move’s struct abilities (key, store, copy, drop), the foundation of secure smart contract development. Now, let’s level up and unlock Aptos Objects, the framework that powers everything from NFTs to fungible tokens.

This tutorial takes it even further by going deep into one of the most powerful concepts in Aptos Move: Objects. Move Objects provide a flexible and secure way to manage on-chain data, enabling developers to build more sophisticated and composable DApps. Whether you're looking to create advanced NFTs, manage complex game assets, or build intricate DeFi protocols, understanding Move Objects is crucial.

Composable DApps: DApps and protocols that can interact with each other seamlessly, much like Lego bricks. If data is structured as well-defined Objects with clear interfaces, one DApp can easily read from or write to another DApp's objects (with proper authorization), leading to a highly interconnected and innovative ecosystem. For instance, an NFT created in one DApp could be used as collateral in a lending protocol built by another team, precisely because it's a well-understood "Object."

By the end of this hands-on guide, you will have a comprehensive understanding of what Move Objects are, how they function, and how to apply them in your DApp development. We'll explore their core capabilities, walk through practical code examples, and discuss best practices to help you build smarter and more securely on Aptos.

Let's begin.

Understanding Move Objects
At its heart, Move is a "resource-oriented" programming language. Unlike traditional object-oriented languages where objects are merely data structures, in Move, resources are first-class citizens that cannot be copied or implicitly discarded; they can only be moved. This fundamental principle is extended and enhanced by Move Objects.

What are Move Objects?
In Aptos Move, an Object is a special kind of resource that acts as a container for other resources. It's safe to also view it as a smart contract account that can hold various assets and data structures, but crucially, it itself is a resource that can be owned and transferred. Imagine what flexibility this brings.

Key characteristics of Move Objects:

  • Self-Contained Entities: Objects group related resources together, allowing them to be treated as a single, cohesive entity on the blockchain.
  • Unique Address: Every object has its own unique address on the Aptos blockchain, derived from its creation. This address allows for direct interaction and referencing.
  • Ownership: Objects have an owner field within their ObjectCore (which we'll discuss shortly). This owner can be an account address or even another object's address, enabling nested ownership structures.
  • Resource Container: Objects can own other resources. This means you can store custom data structs (defined with has key ability) directly under an object's address.

Objects have their own address and can own resources similar to an account. They are useful for representing more complicated data types on-chain as Objects can be used in entry functions directly, and can be transferred as complete packages instead of one resource at a time.

Key Features and Capabilities

Move Objects are designed with flexibility and security in mind, offering several powerful capabilities:

  • Ownership: The owner field within an object's ObjectCore dictates who controls the object. This owner can be an external account or another object, enabling complex ownership hierarchies.
  • Transferability: By default, objects are transferable. However, this can be finely controlled. You can make an object:
    • Ungated Transferable: Freely transferable by its owner.
    • Untransferable: Cannot be transferred at all (e.g., for soulbound tokens).
    • Controlled Transferable: Requires specific permissions or logic for transfer.
    • Linear Transferable: Allows a one-time transfer by the owner.
  • Extensibility: Objects can be designed to be extensible, meaning new resources can be added to their storage after creation. This is crucial for dynamic DApps where an object's properties might evolve over time (e.g., adding new traits to an NFT).
  • Immutability: While objects can be extended, certain aspects of their configuration (like whether they are deletable or initially transferable) are set at creation time and cannot be changed later. This ensures predictable behavior.
  • Deletion: Objects can be made "deletable" at creation. Deleting an object removes it from global storage and can even refund gas costs associated with its storage, promoting efficient resource management on-chain.

*Object Creation and Configuration *
Creating and configuring an object involves using specific functions and references provided by the aptos_framework::object module.

The core of every object is the ObjectCore struct, which is automatically added to any struct declared with has key and used to create an object via object::create_object, object::create_named_object or object::create_sticky_object, depending on the type of object you want to create.

struct ObjectCore has key {
        /// Used by guid to guarantee globally unique objects and create event streams
        guid_creation_num: u64,
        /// The address (object or account) that owns this object
        owner: address,
        /// Object transferring is a common operation, this allows for disabling and enabling
        /// transfers bypassing the use of a TransferRef.
        allow_ungated_transfer: bool,
        /// Emitted events upon transferring of ownership.
        transfer_events: event::EventHandle<TransferEvent>,
    }
Enter fullscreen mode Exit fullscreen mode

This leads us to the types of objects there are.

  1. Normal Object
  2. Named Object
  3. Sticky Object

We’ll explain them in details later in the second part of this article article.

When you create an object, you receive a ConstructorRef, that is, creating an object returns a ConstructorRef, which is a one-time-use capability that allows you to configure the object during its initial setup.

struct ConstructorRef has drop {
    self: address;
    can_delete: bool; //true if object can be deleted. named objects are not deletable
}
Enter fullscreen mode Exit fullscreen mode

This ConstructorRef is vital for:

  • Generating a Signer: object::generate_signer(&constructor_ref) allows the object itself to act as a signer, enabling it to own and manage its own resources.
  • Adding Initial Resources: Moving resources into the object's storage using move_to(&object_signer, MyResource { ... }) .
  • Configuring Capabilities: Creating TransferRef, DeleteRef, or ExtendRef from the ConstructorRef to define the object's behavior. We’ll explain these other refs shortly

Working with Objects in Move

Next, we’ll see the mechanics of interacting with Aptos move objects.

Object Address Generation
An object's address is generated when it's created. This ensures that each object has a unique identifier on the blockchain. The object::create_object function handles this generation and returns a ConstructorRef for the newly created object's address.

Object Storage
Objects, being resources themselves, are stored on the blockchain. When an object is created, its ObjectCore is stored at its unique object address. Any additional resources that the object "owns" are also stored at this same object address. This centralizes all data related to an object under its specific on-chain address.

Object References and Abilities
Move's type system uses "abilities" to define how a struct can be used. For objects, these abilities are crucial:

  • has key: This ability is essential for any struct that you want to store directly under an account's (or object's) address. The ObjectCore itself has key.
  • has store: This ability means a value of this type can be stored in global storage (i.e., on-chain).
  • has copy: Allows values of this type to be copied.
  • has drop: Allows values of this type to be implicitly dropped at the end of their scope.

We explained abilities in details in our last class, they also apply to objects.

Beyond the ConstructorRef, the aptos_framework::object module provides several other important references that grant specific capabilities:

DeleteRef: Grants the ability to delete the object from storage. This reference can only be created at object construction time if the object is configured to be deletable.

struct DeleteRef has drop, store { self: address, }
Enter fullscreen mode Exit fullscreen mode

ExtendRef: Allows adding new resources to the object's storage after its initial creation. This is useful for dynamic objects.

struct ExtendRef has drop, store { self: address, }
Enter fullscreen mode Exit fullscreen mode

TransferRef: Provides control over the object's transferability. This reference can be used to disable or re-enable ungated transfers.

struct TransferRef has drop, store { self: address, }
Enter fullscreen mode Exit fullscreen mode

LinearTransferRef: A one-time-use reference derived from a TransferRef that allows for a single, controlled transfer of the object. This is useful for "soulbound" or single-transfer assets.

struct LinearTransferRef has drop { self: address, owner: address, }
Enter fullscreen mode Exit fullscreen mode

DeriveRef: Used to create "derived objects" from a given object, allowing for hierarchical object structures.

struct DeriveRef has drop, store { self: address, }
Enter fullscreen mode Exit fullscreen mode

Conclusively, we've covered the core concepts of Aptos Move Objects, from their fundamental resource-oriented nature and key characteristics to their powerful features like ownership, transferability, and extensibility. Understanding the ObjectCore and the various Ref types is crucial for configuring and interacting with objects.

Mastering Move Objects isn't just about learning a technical feature; it's about gaining the ability to design sophisticated, composable DApps on Aptos.

In the next part of this series, we'll look into practical code examples, demonstrating how to leverage Normal, Named, and Sticky Objects to build smarter and more securely on Aptos. Stay tuned!

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.