Resources
Soulidity is a set of Sui Move modules deployed under a single package. All state lives in shared objects. The DB is a mirror — on-chain is source of truth.
| Module | Responsibility |
|---|---|
| soul | Core Soul + SoulState shared object. Mint, ownership rotation, active grant list. |
| metadata | SoulMetadata shared object. Active sprite/voice bindings + JSON ext blobs for desktop/web presentation. |
| market | Personal-kiosk marketplace. Publish, list, delist, buy, import, personal-join. |
| grant | SoulGrant delegation. Issue, revoke, scope-mask, expiry, invalidation on transfer. |
| seal_policy | Seal approval entry functions for owner and granted-agent access to Soul and Memory blobs. |
| memory | SoulMemory shared object. Append-only Table<u64, ID> with dynamic blob fields. |
| skills | SoulSkills shared object. Table<String, vector<SkillSlot>> with private/public visibility. |
| collection | SoulCollection shared object + SoulCollectionRight tradeable object. |
Every Soulidity asset is two objects: a Soul NFT held inside the owner's personal kiosk, and a shared SoulState that tracks ownership, grants, and bound sub-object IDs.
// Held inside personal kiosk (kiosk::place / kiosk::take)
public struct Soul has key, store {
id: UID,
name: String,
description: String,
image_url: String,
protected_blob: Blob, // Walrus Blob object (Seal-encrypted content)
provenance_kind: u8, // 0=native, 1=imported, 2=personal-join
origin_ref: Option<String>, // set for personal-join (source NFT type::id)
creator: address,
}
// Shared object — readable by anyone, mutable by owner via grant module
public struct SoulState has key {
id: UID,
soul_id: ID,
creator: address,
creator_royalty_bps: u16, // basis points, max 10 000
current_owner: address,
current_kiosk_id: ID, // personal kiosk holding the Soul
ownership_epoch: u64, // increments on every ownership change
grant_capacity: u64, // max concurrent grants (default 1)
active_grants: vector<ActiveGrantSlot>,
memory_id: Option<ID>, // bound SoulMemory object ID
metadata_id: Option<ID>, // bound SoulMetadata object ID
skills_id: Option<ID>, // bound SoulSkills object ID
collection_id: Option<ID>, // bound SoulCollection object ID
}Persona / voice presentation metadata now lives in a separate shared SoulMetadata object. The owner updates active bindings via market::set_active_sprite / set_active_voice and writes JSON config blobs via metadata::upsert_metadata_blob.
// Shared object — one per Soul
public struct SoulMemory has key {
id: UID,
soul_id: ID,
entries: Table<u64, ID>, // timestamp_key → blob_object_id
entry_count: u64,
}
// Walrus Blob stored as dynamic object field keyed by MemoryBlobKey
public struct MemoryBlobKey has copy, drop, store { timestamp_key: u64 }Entries are addressed by their timestamp_key (milliseconds from Clock, collision-resolved by increment). Writer kinds: 0 = founder (at mint), 1 = owner, 2 = granted agent (requires SCOPE_MEMORY).
// Shared object — one per Soul
public struct SoulSkills has key {
id: UID,
soul_id: ID,
skills: Table<String, vector<SkillSlot>>, // skillName → version history
skill_count: u64,
}
public struct SkillSlot has copy, drop, store {
blob_object_id: ID,
is_public: bool,
deleted: bool,
created_at_ms: u64,
}
// Walrus Blob stored as dynamic object field keyed by SkillBlobKey
public struct SkillBlobKey has copy, drop, store {
skill_name: String,
version_index: u64,
}Skills use append-only versioning. The versionIndex is the 0-based index into the slot vector. Soft delete sets deleted = true but keeps the slot. Public versions are readable without a grant; private versions require SCOPE_SKILLS.
// Shared object — one per collection
public struct SoulCollection has key {
id: UID,
creator: address,
extra_royalty_bps: u16, // stacked on top of per-Soul creator royalty
tradeable: bool, // whether the SoulCollectionRight can be transferred
current_holder: address,
current_holder_kiosk_id: ID,
right_id: ID,
}
// Held inside holder's kiosk
public struct SoulCollectionRight has key, store { ... }Only the collection creator can add Souls (both creator and Soul creator must match). The SoulCollectionRight is a tradeable object that conveys the collection extra royalty claim.
SoulCreated — emitted by market after any mint variant (native, import, personal-join).SoulOwnershipRotated — emitted by soul::rotate_owner on every purchase or transfer. Increments ownership_epoch.SoulGrantIssued / Revoked / Superseded / Expired / Invalidated — full lifecycle from grant module.MemoryEntryAppended — includes timestamp_key, writer_kind, and blob_object_id.SkillVersionAppended / SkillVersionDeleted — includes skill_name, version_index, and is_public.SoulCollectionCreated / SoulAddedToCollection / CollectionHolderUpdated — from collection module.0 — native: Fresh-deploy via market::mint_native_in_personal_kiosk. No prior NFT.1 — imported: Existing Walrus blob imported via market::mint_imported_in_personal_kiosk.2 — personal-join: An existing Sui NFT wrapped via market::mint_joined_in_personal_kiosk. The source NFT is placed into the personal kiosk first; origin_ref records the source type and object ID.