Sui.

Post

Share your knowledge.

harry phan.
Jul 28, 2025
Expert Q&A

How will this solve my problem of reading all the keys of a nested table?

Anyway I can't get the table reference back because

Programmable transaction blocks (PTBs) do not currently allow the use of object references returned from one of its transaction command
``
How will this solve my problem of reading all the keys of a nested table?
  • Sui
0
11
Share
Comments
.

Answers

11
0xduckmove.
Jul 28 2025, 04:56

1. Reading All Keys of a Nested Table

In Sui Move, if you have a linked_table or similar table structure, you typically need a reference to the table object to iterate over its keys. The usual pattern is to call a function that takes a reference to the table and iterates through its keys (see the example below):

fun foo(table: &linked_table::LinkedTable<u64, u8>): u64 {
    let mut res = 0;
    let mut option_key = table.front();
    while (option_key.is_some()) {
        let key = *option_key.borrow();
        res = res + key;
        option_key = table.next(key);
    };
    res
}

Source: context #5


2. PTB Limitation: No Chaining of Returned Object References

You are correct: Programmable Transaction Blocks (PTBs) do not currently allow you to use object references returned from one command as input to another command in the same PTB. This means you cannot, for example, create a table in one command and then immediately use its reference in another command within the same PTB.

This limitation makes it impossible to:

  • Dynamically create a table and then iterate over its keys in a single PTB.
  • Chain operations that require a reference to an object just created or returned in the same transaction block.

3. How Does This Affect Reading All Keys?

  • If you already have the table object reference (e.g., it’s stored in your account), you can call a function that iterates over its keys.
  • If you need to create or fetch the table reference within the same PTB, you cannot use it in subsequent commands in that PTB due to the limitation you mentioned.

4. Workarounds

  • Split into Multiple Transactions:
    • First, create or fetch the table in one transaction.
    • Then, in a separate transaction, use the reference to read or iterate over the keys.
  • Store Table References:
    • Persist table references in an account or another object so you can use them in future transactions.

5. Summary

  • You cannot chain object references in a single PTB.
  • To read all keys of a nested table, you must already have the table reference before the transaction starts.
  • If you need to create or fetch the table, do it in a separate transaction.
2
Best Answer
Comments
.
Benjamin XDV.
Jul 28 2025, 10:29

Reading All Keys from Nested Tables in Sui PTBs

You're facing a fundamental limitation in Sui's Programmable Transaction Blocks (PTBs) - they don't allow using object references returned from previous commands. Here's how to work around this for reading nested table keys:

Current Limitation

PTBs indeed don't support using command outputs as inputs to subsequent commands. This prevents chaining operations like:

  1. Getting a table reference
  2. Using that reference to read keys

Workaround Solutions

1. Pre-fetch All Required References

// Get all needed references before building PTB
let table1_ref = get_table_reference();
let table2_ref = get_nested_table_reference();

// Build PTB with all known references
let ptb = ProgrammableTransactionBuilder::new();
ptb.command(Command::MoveCall {
    arguments: vec![
        Argument::Input(0),  // table1_ref
        Argument::Input(1),  // table2_ref
    ],
    // ... other params
});

2. Use Dynamic Field Lookups

// Get keys via dynamic field queries
let parent_object_id: ObjectID = /* your parent object */;
let dynamic_fields = sui_client
    .dynamic_field_api()
    .get_dynamic_fields(parent_object_id)
    .await?;

3. Two-Phase Approach

Phase 1: Get all table references (client-side) Phase 2: Construct PTB with all known references

4. For Nested Tables

// If you know the nesting structure:
let ptb = ProgrammableTransactionBuilder::new();

// Add commands for each level
ptb.command(Command::MoveCall {
    arguments: vec![
        Argument::Input(0),  // root table
        Argument::Pure(bcs::to_bytes(&key1)?),
    ],
    // ... get nested table ID
});

// Subsequent commands would need the nested table ID pre-known

Key Insight

You must:

  1. Know the structure/depth of nesting beforehand
  2. Pre-fetch all required references before PTB construction
  3. Use client-side logic to stitch together operations that can't be chained in PTBs

Future Solution

The Sui team is working on PTB improvements that may allow:

  • Reference returns between commands
  • More flexible command chaining

For now, you'll need to design your workflow around these constraints, either by pre-fetching data or restructuring your tables to require fewer nested lookups.

7
Comments
.
Owen.
Owen4662
Jul 30 2025, 03:15

PTBs cannot return object references, so you cannot directly read all keys from a nested Table in a single transaction. Instead, maintain a separate vector or Table that stores the keys explicitly when inserting into the nested structure. This allows you to query the key list via an independent read or include it as a transaction output. Dynamic fields or custom indexing patterns are required to work around the limitation of Table enumeration in Sui Move.

7
Comments
.
Alya.
Alya-14
Jul 31 2025, 06:20

PTBs can't return table refs, but you can use sui::table::borrow in a view function or a custom indexer to read all keys of a nested table off-chain. On-chain iteration isn't supported yet.

6
Comments
.
Evgeniy CRYPTOCOIN.
Jul 29 2025, 13:59

Currently, PTBs don’t support using object references returned mid-transaction, so you can’t dynamically fetch nested table keys in one go.

Workarounds:

  1. Pre-fetch keys – Read them beforehand if possible.
  2. Multi-step process – Split into separate transactions.
  3. Off-chain indexing – Use a custom indexer to track nested keys.

Future Fix? Sui may improve PTB flexibility later, but no ETA.

5
Comments
.
Arnold.
Arnold3036
Jul 30 2025, 08:18

PTBs can't return object references mid-execution, but you can:

Workaround

  1. Pre-fetch all keys in a separate query before the PTB.
  2. Use dynamic fields (if possible) for nested data.
// Example: Fetch keys via `table::length` + loop (off-chain)
let len = table::length(&table);
let keys = vector[];
let i = 0;
while (i < len) {
    keys.push_back(table::borrow(table, i));
    i = i + 1;
}
5
Comments
.
Bekky.
Bekky1762
Jul 29 2025, 13:22

Workaround for Nested Table Keys:

  1. Pre-Fetch All References
    Get table IDs before constructing the PTB:

    const parentTable = await client.getObject({ id: PARENT_TABLE_ID });
    const nestedTableIds = parentTable.data?.content.fields.nested_tables;
    
  2. Use Input Instead of Result
    Pass all required table IDs as PTB inputs:

    let txb = TransactionBuilder::new();
    // Use pre-fetched IDs as Input arguments
    txb.move_call(
        package_id,
        module,
        function,
        type_args,
        [Input(nestedTable1), Input(nestedTable2)]
    );
    
  3. Alternative: Client-Side Joins

    // 1. Fetch all tables separately
    const tables = await Promise.all(
      tableIds.map(id => client.getDynamicFields({ parentId: id }))
    );
    // 2. Merge keys client-side
    const allKeys = tables.flat();
    

Why This Works:

  • Avoids PTB's reference-return limitation by treating tables as known inputs
  • Uses Sui's parallel multiGet APIs for efficiency
  • Matches Sui's object-centric model (tables are separate objects)
4
Comments
.
theking.
Aug 23 2025, 09:59

You’ve hit a current limitation of Sui’s Programmable Transaction Blocks (PTBs): they don’t let you grab an object reference created by one command and then feed it directly into another command inside the same PTB. That’s why you can’t just “walk” through a nested table on-chain and pull out all its keys during a transaction.

Here’s how this usually plays out:

Why You Can’t Enumerate Keys in PTBs

  • PTBs are deterministic and single-pass: once you create or return a reference, you can’t reuse it to run arbitrary iteration within the same transaction block.
  • Move tables don’t expose key iteration natively: they’re optimized for lookups by known keys, not for on-chain enumeration. Reading “all keys” isn’t supported because it would break gas predictability and parallelism guarantees.

Common Workarounds

  • Off-chain indexing: Use an indexer (like Sui Explorer APIs, custom indexers, or SDKs) to read and cache all keys off-chain. You then query off-chain and only pass back the keys you care about into PTBs.
  • Application-level design: Instead of storing a large opaque nested table, store a parallel list (vector of keys, or an owned object with references to children) that you maintain as part of contract logic. That way you can enumerate keys by reading this index object.
  • Event-driven tracking: Emit an event whenever you insert a new key. Your off-chain indexer or client listens to events and maintains the full list, which you can later query without on-chain iteration.
0
Comments
.

Do you know the answer?

Please log in and share it.