Derived Objects
Compute derived object IDs from parent objects for deterministic offline derivation.
Derived objects enable deterministic IDs for objects, enabling offline derivation of object IDs. Click here to read more.
To derive an object ID, you can import deriveObjectID function exposed from utils.
import { deriveObjectID } from '@mysten/sui/utils';To derive any object, you need to have its parent's ID (the object from which it was derived), and the key used to generate it.
It is recommended to verify the onchain derived_object::derive_address match your offchain
calculation (at least once when implementing offline calculations), especially for critical cases
like transferring assets.
Deriving using primitive keys
To derive the IDs using primitive types, you can use the built-in types like this, assuming you have
a parent object with ID 0xc0ffee.
// Example 1: Onchain derivation for `0xc0ffee + vector<u8>([0,1,2])
deriveObjectID('0xc0ffee', 'vector<u8>', bcs.vector(bcs.u8()).serialize([0, 1, 2]).toBytes());
// Example 2: Onchain derivation for `0xc0ffee + address('0x111')`
deriveObjectID('0xc0ffee', 'address', bcs.Address.serialize('0x111').toBytes());
// Example 3: Onchain derivation for `0xc0ffee + non-ascii string ("foo")`
deriveObjectID('0xc0ffee', '0x1::string::String', bcs.String.serialize('foo').toBytes());Deriving using custom types
To derive IDs using your custom objects, you can use BCS and the known type IDs.
Assuming a custom struct onchain (for the key) being:
public struct DemoStruct has copy, store, drop { value: u64 }you can derive it by doing:
// Assuming we wanted to derive for key `DemoStruct { value: 1 }`.
const bcsType = bcs.struct('DemoStruct', {
value: bcs.u64(),
});
const key = bcsType.serialize({ value: 1 }).toBytes();
// Derive the object ID for the key `DemoStruct { value: 1 }`.
deriveObjectID('0xc0ffee', `0xc0ffee::demo::DemoStruct`, key);Deriving with fieldless structs
In Move, structs with no user-defined fields automatically get a dummy_field: bool injected by the
compiler. This means their BCS encoding is not empty. It is a single 0x00 byte (the encoding of
false). You can treat this as a constant.
A real-world example is 0x2::coin_registry::CurrencyKey<T>, which is a fieldless generic struct
used to derive Currency objects from the coin registry (0xc) based on their type:
// Onchain: `public struct CurrencyKey<phantom T>() has copy, store, drop`
// The compiler injects `dummy_field: bool`, always `false`.
const key = new Uint8Array([0]);
const coinType = '0x2::sui::SUI';
const currencyId = deriveObjectID('0xc', `0x2::coin_registry::CurrencyKey<${coinType}>`, key);This applies to any struct with no fields. Phantom type parameters do not add any BCS-encoded data,
so the key is always new Uint8Array([0]).