Last updated
Last updated
Sui authentication mechanisms ensure only you can use objects owned by you in Sui Move calls. To use an object in Sui Move calls, pass them as parameters to an . Similar to Rust, there are a few ways to pass parameters, as described in the following sections.
There are two ways to pass objects by reference: read-only references (&T
) and mutable references (&mut T
). Read-only references allow you to read data from the object, while mutable references allow you to mutate the data in the object.
In the preceding function signature, from_object
can be a read-only reference because you only need to read its fields. Conversely, into_object
must be a mutable reference since you need to mutate it. For a transaction to make a call to the copy_into
function, the sender of the transaction must be the owner of both from_object
and into_object
.
Although from_object
is a read-only reference in this transaction, it is still a mutable object in Sui storage--another transaction could be sent to mutate the object at the same time. To prevent this, Sui must lock any mutable object used as a transaction input, even when it's passed as a read-only reference. In addition, only an object's owner can send a transaction that locks the object.
The take_from_sender<T>
function takes an object of type T
from the global storage created by previous transactions. However, if there are multiple objects of the same type, take_from_sender<T>
is no longer able to determine which one to return. To solve this problem, use two new, test-only functions. The first is tx_context::last_created_object_id(ctx)
, which returns the ID of the most recently created object. The second is test_scenario::take_from_sender_by_id<T>
, which returns an object of type T
with a specific object ID.
Unit test for interacting with multiple objects of the same type in tests:
The preceding code creates two objects. Note that right after each call, it makes a call to tx_context::last_created_object_id
to get the ID of the object the call created. At the end, id1
and id2
capture the IDs of the two objects. Next, retrieve both of them and test the copy_into
function:
This uses take_from_sender_by_id
to take both objects using different IDs. Use copy_into
to update the value for obj1
using the value for obj2
. You can verify that the mutation works:
You can also pass objects by value into an entry function. By doing so, the object is moved out of Sui storage. It is then up to the Sui Move code to decide where this object should go.
There are two ways to handle a pass-by-value Sui object in Move:
delete the object
transfer the object
Delete the object
Define a function in the ColorObject
module that allows us to delete the object:
The object unpacks and generates individual fields. You can drop all of the u8 values, which are primitive types. However, you can't drop the id
, which has type UID
, and must explicitly delete it using the object::delete
API. At the end of this call, the object is no longer stored on-chain.
To add a unit test for it:
Option 2. Transfer the object
The owner of the object might want to transfer it to another address. To support this, the ColorObject
module needs to define a transfer
function:
You cannot call transfer::transfer
directly as it is not an entry
function.
Add a test for transferring too. First, create an object in the account of the owner
, and then transfer it to a different account recipient
:
Note that in the second transaction, the sender of the transaction should still be owner
, because only the owner
can transfer the object that it owns. After the transfer, you can verify that owner
no longer owns the object, and recipient
now owns it:
Since every must include UID
as its first field, and the does not have the drop
ability, the Sui object struct type cannot have the ability either. Hence, any Sui object cannot be arbitrarily dropped and must be either consumed (for example, transferred to another owner) or deleted by , as described in the following sections.
If the intention is to actually delete the object, unpack it. You can do this only in the module that defined the struct type, due to Move's . If any field is also of struct type, you must use recursive unpacking and deletion when you unpack the object.
However, the id
field of a Sui object requires special handling. You must call the following API in the module to signal Sui that we intend to delete this object:
The first part of the example repeats the example used in , and creates a new ColorObject
and puts it in the owner's account. The second transaction gets tested. It retrieves the object from the storage and then delete it. Since the object is deleted, there is no need (in fact, it is impossible) to return it to the storage. The last part of the test checks that the object is indeed no longer in the global storage and hence cannot be retrieved from there.