
The latest-state pattern is one of the most important techniques for anyone working with Sui object data. This technique generalizes to every Sui object type and forms the backbone for any analysis rooted in the chain’s actual state. Every asset—whether a coin, NFT, or protocol object—exists as a Move object that evolves through a sequence of versions.
Each mutation creates a new version, deleted objects remain visible with object_status = 'Deleted', and there is no separate balance table or account registry keeping track of state elsewhere. As a result, the canonical truth for any asset is simply the row with the highest version number. If you want to know “what does this object look like right now?”, the answer is always: find its latest version.
This structural choice gives Sui enormous flexibility but also shapes how analysts must work with the data. Tasks like fetching the current owner or metadata of an object become trivial once you understand the pattern. But tasks like reconstructing transfers, ownership histories, or application-level flows require walking through the full sequence of versions—something covered in the previous post.
The Pawtato Heroes example highlights why the latest-state pattern is so essential: the latest version reveals the object’s current metadata and owner, but because objects can be owned by other objects, the last modifying transaction’s sender is often the real controller.
object_id: 0xHERO...123
object versions
+-----------------------------------------------+
| |
version 1 version 2 version 3 (latest)
+--------+ +--------+ +------------------------+
|owner:A | |owner:X | → |owner:Y (wrapper obj) |
|meta:v1 | |meta:v1 | |meta:v2 |
+--------+ +--------+ +------------------------+
^ ^ ^
| | |
Created Mutated Mutated
(ownership changed,
but to an object)
transaction producing version 3
-----------------------------------------
tx_digest: 0xTX...789
sender: 0xREAL_OWNER ← true controller
-----------------------------------------
↑
|
previous_transaction
on version 3 object row
Latest-state logic:
- MAX(version) = 3 → latest object row (owner:Y, meta:v2)
- But owner:Y is another object (wrapper/vault)
- Join version 3's previous_transaction → transaction.sender
- Effective owner = 0xREAL_OWNER
Below is a practical pattern for retrieving the latest version and owner for a Sui NFT collection Pawtato Heroes. The query can be found on Dune here. This example demonstrates how to apply latest-state logic to an NFT collection by tracking ownership changes that occur through Mutated versions, and resolving the true owner by joining the object’s most recent version to the transaction that produced it.
WITH params AS (
SELECT
DATE '2025-10-30' AS start_date,
CURRENT_DATE AS end_date
),
-- All relevant HERO object versions in the date window
base AS (
SELECT
o.object_id,
o.version,
o.object_status,
o.owner_address, -- may be an intermediary object
o.timestamp_ms,
o.type_,
o.object_json,
o.previous_transaction AS tx_digest,
from_unixtime(CAST(o.timestamp_ms AS DOUBLE) / 1000.0) AS updated_at_utc
FROM sui.objects o
CROSS JOIN params p
WHERE o.type_ = '0xe0fa7b75a3dc8137b38bceb0c0c21c10e0f57c408fe9068694f58fd21e071925::pawtato_heroes::HERO'
AND o.object_status IN ('Created', 'Mutated') -- ownership may change on Mutated
AND o.date >= p.start_date -- efficient partition pruning
AND o.date < p.end_date
),
-- Latest version per HERO
latest AS (
SELECT
object_id,
MAX(version) AS max_version
FROM base
GROUP BY object_id
),
-- Date-windowed transactions (prevents full-table scan)
tx_window AS (
SELECT
t.transaction_digest,
t.sender,
t.timestamp_ms AS tx_timestamp_ms,
from_unixtime(CAST(t.timestamp_ms AS DOUBLE) / 1000.0) AS tx_timestamp_utc
FROM sui.transactions t
CROSS JOIN params p
WHERE t.date >= p.start_date
AND t.date < p.end_date
)
-- Final latest state + effective owner
SELECT
b.object_id,
b.version,
b.object_status,
b.owner_address, -- raw object owner (could be another object)
b.updated_at_utc,
b.type_,
b.object_json,
b.tx_digest,
tx.sender AS effective_owner, -- true controller of the NFT
tx.tx_timestamp_utc AS last_tx_at_utc
FROM base b
JOIN latest l
ON b.object_id = l.object_id
AND b.version = l.max_version
LEFT JOIN tx_window tx
ON b.tx_digest = tx.transaction_digest;
This query works by first collecting all relevant Pawtato HERO object versions—both Created and Mutated. The date window is recent because the collection launched October 2025 which makes the dataset small and efficient to scan. It then identifies the latest version of each object by selecting the maximum version per object_id, which represents the current on-chain state of that NFT.
To resolve the true owner, the query pulls in a date-filtered slice of sui.transactions and joins each object’s most recent previous_transaction to the corresponding transaction record. This allows the query to enrich the final result with full object_json metadata, the transaction that last updated the object, and most importantly the sender of that transaction—who is often the actual controlling address, even when the object’s recorded owner is an intermediate wrapper object.
Share Dialog
No comments yet