Skip to main content

Address-Owned Objects

Address-owned objects are owned by a 32-byte address. 32-byte addresses are either an account address derived from a particular signature scheme or an object ID. An address-owned object is only accessible to its owner. You can transfer objects that you own to different addresses.

Create address-owned objects

Use these transfer module functions to create address-owned objects:

public fun transfer<T: key>(obj: T, recipient: address)
public fun public_transfer<T: key + store>(obj: T, recipient: address)

An object's ownership can change over the life of that object, either by adding it as a dynamic object field, transferring it to a different address, or making it immutable. However, after you create an object and set its ownership, it cannot be shared.

public fun create(value: u64, recipient: address, ctx: &mut TxContext) {
transfer::public_transfer(
Object { id: object::new(ctx), value },
recipient,
)
}

When to use address-owned objects

Use address-owned objects when you need:

  • Single ownership

  • Better performance than shared objects

  • Avoidance of consensus sequencing

Interact with address-owned objects

You can access address-owned objects in 2 different ways depending on whether the address owner of the object corresponds to an address or an object ID.

If the address owner of the object is an account address, then you can use and access it directly as an owned object during the execution of a transaction signed by that address. Other addresses cannot access owned objects in any way.

If the address owner of the object corresponds to an object ID, then you must access and dynamically authenticate it during the execution of the transaction using the mechanisms defined in Transfer to Object.

To interact with an address-owned object through the CLI, first view the objects you own:

$ export ADDR=`sui client active-address`
$ sui client objects $ADDR

You can see sui::transfer::public_transfer function used in the color_object example module tests. The test creates a new address-owned ColorObject object, then calls public_transfer to transfer it to the owner's address.

Save the color_object example code, then publish the ColorObject code on-chain using the Sui CLI:

tip

Beginning with the Sui v1.24.1 release, the --gas-budget option is no longer required for CLI commands.

$ sui client publish $ROOT/examples/move/color_object --gas-budget <GAS-AMOUNT>

Set the package object ID to the $PACKAGE environment variable, if you have it set. Then create a new ColorObject:

$ sui client call --gas-budget <GAS-AMOUNT> --package $PACKAGE --module "color_object" --function "create" --args 0 255 0

Set the newly created object ID to $OBJECT. To view the objects in the current active address:

$ sui client objects $ADDR

You can see that it is now owned by your address by querying the object information and viewing the Owner field in the output:

$ sui client object $OBJECT

Test address-owned objects

The following test creates an address-owned object, transfers it to the owner, then verifies that the owner field is correct:

#[test]
fun test_transfer() {
let mut ts = ts::begin(@0x0);
let sender = @0xA;
let recipient = @0xB;

// Create a ColorObject and transfer it to sender.
{
ts.next_tx(sender);
let c = new(255, 0, 255, ts.ctx());
transfer::public_transfer(c, @0xA);
};

// Transfer the object to recipient.
{
ts.next_tx(sender);
let object: ColorObject = ts.take_from_sender();
transfer::public_transfer(object, recipient);
};

// Check that sender no longer owns the object.
{
ts.next_tx(sender);
assert!(!ts.has_most_recent_for_sender<ColorObject>(), 0);
};

// Check that recipient now owns the object.
{
ts.next_tx(recipient);
assert!(ts.has_most_recent_for_sender<ColorObject>(), 0);
};

ts.end();
}