Introduction

Everything Theory is a protocol and a blockchain specification centered around a novel class of non-fungible tokens (NFTs).

Protocol of Everything

These new tokens, called object tokens or simply objects, are dynamic in nature: they can be modified, evolve over time, and interact with other tokens, offering significantly more functionality than traditional NFTs.

Each object is built from elements, created within a set, and assigned a specific kind. Creators can build sets using elements and kinds from different authors, enabling efficient and collaborative on-chain creation.

The protocol introduces the concept of space. Beyond ownership, tokens now also have a position, meaning they can not only be held by accounts but also exist in specific locations within the protocol.

Each blockchain supported by the protocol is treated as a universe, referred to as a universe chain. Since the protocol explains how time and space expand, how objects are created from elements, and how they interact, it is often called the Protocol of Everything (PRE).

Previous Network

While decentralized storage solutions like IPFS and Arweave address the centralization issues of static NFTs, challenges remain for dynamic NFTs. For instance:

  1. A gift card NFT that updates its balance in real-time.
  2. A PFP NFT that can be accessorized with NFTs from other issuers (e.g., hats, T-shirts).

These cases require decentralized, secure solutions for NFT mutability and interoperability, which are key to broader NFT adoption.

The Previous Network addresses these challenges in a fully decentralized manner. It consists of three primary types of nodes:

  • Probes: Detect activities on universe chains and relay them to telescopes, functioning like bridges.
  • Telescopes: Validator nodes responsible for validating and processing transactions.
  • Satellites: Nodes that serve digital assets related to tokens and elements, allowing users and applications to access this data.

The Previous Network, also referred to as the Previous Chain or simply Previous, features the Object Virtual Machine (OVM)—a specialized virtual machine designed to process the digital assets of tokens. The OVM ensures deterministic and verifiable computations, providing a secure foundation for expanding NFT use cases.

Previous differs from universe chains by focusing on imaging, or the computation of underlying assets of objects. While Ethereum is often called a "world computer," Previous acts like a "world camera," and is sometimes referred to as the observer chain.

Unlike Layer 2 solutions focused on scaling, Previous adds programmability and data availability to token assets—areas that neither Layer 1 nor Layer 2 chains typically prioritize. This capability enables tokens to be applied in a wider range of engaging use cases on both layers.

Primitives

Several fundamental types are key to understanding and working within the protocol.

  • Oid: A unique identifier for objects within a universe.
  • Revision: Denotes the version of an object's state.
  • Selector: Specifies a particular underlying asset of an object.
  • Meta: Metadata containing key information about an object.
  • Time: Represents a specific moment in the universe's timeline.
  • Position: Defines the location within a universe.
  • Adjacency: Defines how many objects of a certain kind can be accepted in a relation, acting as a core unit in the adjacency specification.

In addition, there are common primitives types used throughout the protocol:

  • uint8, uint32, uint64, uint128, uint256: Unsigned integers of lengths.
  • bytes32: A 32-byte fixed-length array.
  • bytes: A variable-length array.

Oid

Oid is the unique identifier of an object within a universe.

Representation

Oid can be represented by the following structure:

struct Oid {
    uint64 set;
    uint64 id;
}

Fields

TypeFieldDescription
uint64setThe set ID.
uint64idThe object ID.

ID

Both the set and the object ID are represented as 64-bit unsigned integers (uint64).

The valid range for an ID is [1, 2^64 - 2].

Two special values are reserved for specific purposes:

  • uint64::MIN (0): Serves as a wildcard, indicating any valid ID.
  • uint64::MAX (2^64 - 1): Represents infinity or total.

Encoding

Oid can be encoded as a uint128:

(uint128(set) << 64) | uint128(id)

Written Format

Oid is typically written in dot-decimal format, like {set}.{id}.

For example:

  • 17.1: Represents the object with ID 1 within set 17.

For meta objects, the {set}. can be replaced with its name:

  • kind 1: Represents the kind object with ID 1 within the set of kinds.
  • relation 17: Represents the relation object with ID 17 within the set of relations.

Revision

Revision is an index that indicates the version of an object’s state. It is represented by a 32-bit unsigned integer (uint32).

The valid range for a revision is [1, 2^32 - 2].

Two special values are reserved for specific purposes:

  • uint32::MIN (0): Indicates that the object does not exist or refers to the latest revision of the object.
  • uint32::MAX (2^32 - 1): Indicates that the object has been destroyed.

When an object is created, it starts with a revision of 1. As the object evolves or undergoes changes, its revision is incremented to reflect each state change.

Selector

A Selector is a 32-bit unsigned integer (uint32) that identifies an underlying asset of an object. It is calculated from the function signatures of asset functions within a kind contract.

uint32::MIN (0) and uint32::MAX (2^32 - 1) are not considered valid selectors.

Calculation

The calculation process follows the same method used in Ethereum:

bytes4(keccak256(sig))

In this context, the function signatures (sig) are determined differently: since asset functions do not have arguments, the signature is simply the function name without parentheses.

For example, given the following kind contract:

@kind
class Hat {
    // ...

    meta(): Json {
        // ...
    }

    picture(): Image {
        // ...
    }
}

The selectors are calculated as follows:

bytes4    selMeta = bytes4(keccak256("meta"));    // 0x0144b03a
bytes4 selPicture = bytes4(keccak256("picture")); // 0xeb0568a6

Time

Time represents a specific moment within a universe's timeline.

Representation

Time is conceptually similar to a tuple of (block_num, txn_index, log_index), providing a structured way to track when events occur.

struct Time {
    uint64 block;
    uint32 second;
    uint32 third;
}

Fields

TypeFieldDescription
uint64blockThe number of the block on the universe chain where the event occurred.
uint32secondThe index of the transaction within that block where the event was logged.
uint32thirdThe index of the log entry within the transaction that records the event.

Encoding

The Time structure can be encoded into a u128:

(uint128(block) << 64) | (uint128(second) << 32) | uint128(third)

Written Format

Time is commonly written in the format of block:second:third.

For example:

  • 0:0:0 - The beginning of a universe.
  • 123456:0:0 - An event occurring at block 123456, transaction 0, log entry 0.
  • 122456:7:8 - An event occurring at block 122456, transaction 7, log entry 8.

Position

Position represents the location of an object within a universe, classified into five main categories:

  • Void: The object exists nowhere.
  • Space: The object is located within a block of space, with optional specific coordinates.
  • Object: The object is in relation to another object.
  • World: The object has entered a world.
  • Outerverse: The object has exited the current universe.

The primary part of a location is called the domain, while the secondary part, called coordinates, provides more specific location details when applicable.

Representation

A position is represented by the following structure:

struct Position {
    uint64 domain;
    uint64 coord;
}

Fields

TypeFieldDescription
uint64domainThe domain ID, representing the primary part of a location.
uint64coordThe coordinates within the domain, if applicable.

Domain ID

Each category of location is assigned a unique category ID (cat) and indicated by a letter (indicator). The index specifies the primary part of the location under that category.

CategoryIndicatorCatIndex
Void's'0index = 0
Space's'0index = block ID
Object'o'1index = set ID
World'w'127index = world ID
Outerverse'u'128index = universe ID

The domain ID is constructed from a combination of cat and index, forming a unique unsigned 64-bit integer:

uint64(cat) << 56 | uint64(index)

Encoding

A position can be encoded as a uint128:

(uint128(domain) << 64) | uint128(coord)

Written Format

Positions are typically written in dot notation as {letter}.{index}.{coord}. For void positions, you can use void or 0, and the trailing 0 can be omitted.

Examples:

Dot NotationAlternativeDescription
s.0.0void or 0The void.
s.12.34:56Block 12, coordinates (34, 56).
o.17.1Relation to object 17.1.
w.17.0w.17World 17.
u.8453.0u.8453Universe 8453.

Adjacency

Adjacency is a structure that defines how many objects of a particular kind can be accepted within a relation. It serves as an atomic unit in the adjacency specification, helping to define object interfactions within the protocol.

Representation

The adjacency structure is defined as follows:

struct Adjacency {
    uint64 kind;
    uint32 degMin;
    uint32 degMax;
}

Fields

TypeFieldDescription
uint64kindThe ID of the kind of objects that can be accepted.
uint32degMinThe minimum number (inclusive) of objects of that kind.
uint32degMaxThe maximum number (inclusive) of objects of that kind.

Encoding

A single adjacency structure can be encoded into a uint128;

(uint128(kind) << 64) | (uint128(degMin) << 32) | uint128(degMax)

Elements

Elements are the fundamental building blocks of objects in the protocol.

Several types of elements exist within a universe:

  • Material: Immutable content such as images, audio, structured data, and more. These are stored on the Previous chain and referenced on universe chains using a material hash.

  • Information: Arbitrary data associated with an object.

  • Value: Represents an amount of fungible tokens on a universe chain. Information and materials linked to values can be accessed during runtime in smart contracts on the Previous chain.

  • Artifact: Represents non-fungible tokens (NFTs) on a universe chain. Information and materials linked to artifacts can be accessed during runtime in smart contracts on the Previous chain.

All elements are 32 bytes in length. Values and Artifacts are collectively referred to as token elements due to their token-based nature.

Material

A Material represents digital content in various forms, such as images, audio files, JSON data, and other media types.

A 32-byte hash, known as the material hash, is generated from the content using a specific hashing algorithm. The original content from which this hash is derived is referred to as the preimage or the content of the material.

On universe chains, material hashes are typically used as elements within objects. On the Previous chain, the actual material content can be retrieved and processed to compute object assets.

Representation

The material structure1 is defined as follows:

#![allow(unused)]
fn main() {
pub struct Material {
    hasher: u32,
    content_type: Bytes32,  // alias of [u8; 32]
    content: Bytes,         // alias of Vec<u8>
}
}

Fields

TypeFieldDescription
u32hasherThe identifier for the hashing algorithm.
Bytes32content_typeA string specifying the content type, right-padded to 32 bytes with zeros.
BytescontentThe actual digital content.

Hashing

The material hash is computed as follows:

#![allow(unused)]
fn main() {
let hash_func = ...; // get hash function by material.hasher
let hash = hash_func(material.content);
}

Hashers

The following table lists the currently supported hashing algorithms:

HasherDescriptionHash FunctionImplementation Status
1SHA256sha256Done
2IPFS Content IDipfs_cidPlanned
3Arweave Transaction IDarweave_txnidPlanned

Additional hashers may be introduced in the future.


1

This structure is expressed in Rust syntax, as defined and utilized on the Previous chain.

Information

An Information element represents an arbitrary piece of 32-byte data.

Information elements can be used to store part of an object's state, which can be accessed in both set contracts on the universe chain and kind contracts on the Previous chain.

Value

A Value element represents an amount of fungible tokens on a universe chain. Values standardize fungible tokens within the protocol, making them programmable both on universe chains and on the Previous chain.

Before a value can be used in objects, it must be registered in the Element Registry, providing the token standard, contract address, and related materials during registration.

For example, if you're creating an NFT representing a gift card, you can conceptualize it as an object composed of two elements: a value element representing the face value, say 20 $USDC, and a material element representing the card’s background image.

On the universe chain, the set contract holds the token for the object (meaning whoever owns the object can withdraw or use the $USDC). On the Previous chain, the kind contract can read the current balance from the Value element, load the token image, resize it, and overlay it on the background image.

Representation

A Value is represented by the following structure:

struct Value {
    uint64 token;
    uint192 amount;
}

Fields

TypeFieldDesc
uint64tokenThe ID of the fungible token contract.
uint192amountThe amount of the fungible token.

The higher 8 bits of the token field are used to indicate the token standard. The lower 56 bits of the token field are an index to identify a specific token among all tokens registered under the same standard.

Token Standards

Currently supported standards for fungible tokens include:

Standard TypeStandard ValueDescription
TOKEN_STD_NATIVE1Native token (e.g., ETH).
TOKEN_STD_202ERC-20-like tokens(e.g., USDC).

Additional token standards can be registered by users, allowing for future token types to be supported.

Encoding

Value can be encoded as a uint256 or a bytes32::

uint256 encoded1 = (uint256(token) << 192) | uint256(amount);
bytes32 encoded2 = bytes32((uint256(token) << 192) | uint256(amount));

Limitation

The amount field is allocated 192 bits, which allows for a maximum value of 2^192 - 1. While this is large enough for most scenarios, tokens with very high decimal places might approach this upper limit, potentially leading to an overflow or other boundary-related issues in cases of extremely high precision.

Artifact

An Artifact element represents one or more non-fungible tokens (NFTs) on a universe chain. Artifacts standardize NFTs within the protocol, making them programmable on both universe chains and the Previous chain.

Before an artifact can be incorporated into objects, it must first be registered in the Element Registry. During registration, essential details such as the token standard, contract address, ID range, and associated materials must be provided.

Representation

The Artifact structure is defined as follows:

struct Value {
    uint64 token;
    uint64 id;
    uint128 amount;
}

Fields

TypeFieldDesc
uint64tokenThe identifier of the non-fungible token contract.
uint64id The ID of the non-fungible fungible token.
uint128amountThe amount of the non-fungible token, or 1 if not applicable.

The higher 8 bits of the token field are used to indicate the token standard. The lower 56 bits of the token field are an index to identify a specific token among all tokens registered under the same standard.

Token Standards

Currently supported standards for non-fungible tokens include:

Standard TypeStandard ValueDescription
TOKEN_STD_7213ERC-721-like token.
TOKEN_STD_11554ERC-1155-like tokens.

Additional token standards can be registered by users, allowing for future token types to be supported.

Encoding

Artifact can be encoded as a uint256 or a bytes32::

uint256 encoded1 = (uint256(token) << 192) | (uint256(id) << 128) | uint256(amount);
bytes32 encoded2 = bytes32((uint256(token) << 192) | (uint256(id) << 128) | uint256(amount));

Limitations

The id field is constrained to 64 bits, limiting the maximum ID value. In ERC-721 and ERC-1155 standards, the token ID is typically represented as a uint256, which allows for larger ID values compared to the protocol's 64-bit limit.

Additionally, the amount field is limited to 128 bits. This creates a constraint on the maximum token amount that can be represented, whereas the ERC-1155 and ERC-721 standards use a uint256 for amounts, providing a larger range for representing token quantities.

Objects

Object tokens, or objects, are the novel class of non-fungible tokens central to the protocol.

Objects are constructed from elements, created within sets, and assigned a specific kind. Operations such as relations and transforms can be registered and applied to or between objects, allowing them to evolve and interact.

Meta objects, including sets, kinds, relations, and transforms, govern the lifecycle, structure, and behavior of other objects. Objects that are not meta objects are referred to as plain objects.

Objects can also be classified based on their creation time:

  • Original objects: Created during the early stages of the universe.
  • Emergent objects: Created after the early stages.

Object

The OpenZeppelin documentation1 provides a clear explanation to help distinguish between token contracts and tokens:

Much of the confusion surrounding tokens comes from two concepts getting mixed up: token contracts and the actual tokens.

A token contract is simply an Ethereum smart contract. "Sending tokens" actually means "calling a method on a smart contract that someone wrote and deployed." Essentially, a token contract is a mapping of addresses to balances, along with methods for adding or subtracting from those balances.

These balances represent the tokens themselves. Someone "has tokens" when their balance in the token contract is non-zero. These balances could be considered money, game experience points, ownership deeds, or voting rights, with each type stored in different token contracts.

In light of this, an ERC-721 token is a token defined by an ERC-721-compliant contract, which maintains a mapping between a token's ID, its owner and a URI pointing to its metadata. The structure of the mapping looks like this:

id => (owner, uri)

By comparison, an object is a token defined by a contract conforming to the object token standard. This contract maintains mappings for the object’s ID, its owner, and its state. Additionally, objects have a position property that tracks their location or relationship with other objects. This is managed by the OOPS (Object Operating and Positioning System), a core contract in the protocol. The mappings are as follows:

id => (owner, state)  // maintained by the set contract
id => pos             // maintained by OOPS

The state of an object is composed of two types of information:

  1. Metadata: Information about the object’s revision, kind, and set objects.
  2. Elements: The actual data that make up the object.

The address of the defining contract is stored as an information element within the object's set object, and is typically referred to as the set contract.

There is also another type of contract, executed on the Previous chain, responsible for computing the object's assets. The hash of this contract is stored as a material element of the object's kind, and it is commonly known as the kind contract.

Representation

An object can be represented by the following structure.

struct Object {
    uint256   owner;
    Meta      meta;
    bytes32[] elems;
    uint256   pos;
}
Note that this structure is pseudocode for illustration purposes. In practice, the pos property is handled by the OOPS contract, implemented by the protocol developer. Meanwhile, the other fields are handled by set contracts created by users, who have flexibility in how they manage the properties.

id

The ID of an object is assigned by the set contract at the time of creation and must remain constant throughout the object's lifecycle. Although this field is essential, its implementation are left to the discretion of users.

owner

The owner field is stored as a uint256 to ensure compatibility with various universe chains. This allows for flexibility in managing ownership across different blockchains.

On Ethereum, ownership is typically represented by an address type. To convert an address into a uint256, the following Solidity code can be used:

uint256(uint160(address(owner)));

The owner field is updated when an object is transferred. Additionally, ownership might change when an object becomes related or unrelated to other objects, or when it enters or exits a space or world, depending on how the governing contract (such as a relation, space, or world contract) is structured.

meta

The meta field contains metadata about the object and is represented by a Meta structure, as defined below:

struct Meta {
    uint32 flags;
    uint32 rev;
    uint32 kindRev;
    uint32 setRev;
    uint64 kind;
    uint64 set;
}

The fields of a Meta structure include:

  • flags: Status flags of the object.
  • rev: The revision number of the object.
  • kindRev: The revision number of the object's kind object.
  • setRev: The revision number of the object's set object.
  • kind: The ID of the kind object, which defines the object's structure and behavior.
  • set: The ID of the set object, where the object was created.

A Meta structure can be encoded into a uint256 as follows:

(uint256(meta.flags)   << 224) |
(uint256(meta.rev)     << 192) |
(uint256(meta.kindRev) << 160) |
(uint256(meta.setRev)  << 128) |
(uint256(meta.kind)    << 64)  |
 uint256(meta.set)

elems

The elems field is an array of bytes32 values representing the elements of an object at a specific revision.

The length of this array and the interpretation of each element are governed by the stateSpec of the object's kind. The specific revision of the kind object is determined by the meta.kind and meta.kindRev fields.

pos

The pos field is a uint256 value that records the object's location, along with additional associated information.

The lower 128 bits are reserved for the Position primitive, which specifies the object's exact location. The higher 128 bits store additional data. This allows the pos field to not only reflect spatial coordinates but also offer room for contextual data related to the operation.

The default value for pos is 0, indicating that newly created objects initially reside in the void. As objects move, or become related to other objects, the pos field is updated to reflect their new location or relationship within the universe.

Operations

Objects can undergo various operations, ranging from modifications to ownership and interactions with other objects. These operations are either unary (affecting a single object) or inter-operations (interactions between objects).

Unary Operations

Unary operations are applied to individual objects and are defined by set contracts. These operations update specific fields related to the object's state or ownership.

OperationDescriptionFields Affected
transferTransfers the ownership of the object.owner
updateUpdates the elements of the object.meta.rev, elems
upgradeApplies new versions of the object's kind and/or set.meta.rev, meta.kindRev, meta.setRev
touchIncrements the object's revision without changing state.meta.rev

Inter-Operations

Inter-operations involve interactions between objects, are governed by the OOPS contract. These operations can modify relationships, positioning, and movement between spaces and universes.

OperationDescriptionFields Affected
moveMoves the object in space.pos
relateMoves the object into a relation with another object.meta.rev, pos, owner
unrelateMoves the object out of a relation with another object.meta.rev, pos, owner
enterMoves the object into a world.pos, owner
leaveMoves the object out of a world.pos, owner
jumpMoves the object out of the current universe for another, verse-jumping.pos, owner
dropMoves the object into the current universe from another, because of a verse-jumping.pos, owner

Compatibility

Objects are a next-generation NFT standard, but they can easily be made compatible with previous NFTs. By implementing the interfaces required by prior standards (e.g., ERC-721 or ERC-1155) alongside those needed for a valid set contract, developers can ensure that objects function like traditional tokens and integrate seamlessly with existing wallets, marketplaces, and block explorers, all with minimal effort.


1

https://docs.openzeppelin.com/contracts/5.x/tokens#but_first_coffee_a_primer_on_token_contracts

Set

Sets are the objects from which other objects are created.

All set objects originate from a special object called the Set of Sets, which is governed by the Set Registry contract. The Set of Sets itself is considered to have been created from its own structure.

Each set adheres to the Kind of Set, which defines the structure, interactions, and asset computations of set objects.

During the early stages of the universe, several original sets, including the Set of Sets, were created. From that point onward, more objects were either directly or indirectly created from these sets.

Creation

Set objects are created unpon registration, they are initialized as follows:

id

For original sets, the id field is predefined by constants in the protocol:

uint64 constant ID_SET_OF_SPACE     = 0;
uint64 constant ID_SET_OF_SET       = 1;
uint64 constant ID_SET_OF_KIND      = 2;
uint64 constant ID_SET_OF_RELATION  = 3;
uint64 constant ID_SET_OF_TRANSFORM = 4;

For emergent sets, created dynamically later, their IDs are allocated from a specific range:

uint64 constant ID_SET_EMERGENT_MIN = 17;
uint64 constant ID_SET_EMERGENT_MAX = type(uint56).max;

The ID is constrained to values no greater than 2^56 - 1 to ensure that the upper 8 bits of the uint64 remain unset. This applies to all meta objects, allowing combination with an 8-bit category value to form an efficient uint64 identifier.

meta

The meta field is initialized in the following manner, applicable to both original and emergent sets.

meta.flags      = 0;
meta.rev        = 1;
meta.kindRev    = latestKindOfSet();    // The latest revision of the Kind of Set
meta.setRev     = latestSetOfSet();     // The latest revision of the Set of Sets
meta.kind       = ID_KIND_OF_SET;
meta.set        = ID_SET_OF_SET;

Since the kind and set objects always point to their latest revisions, the revision numbers for these fields might be incremented for later-created sets.

elems

According to the Kind of Set, a set object is composed of two elements:

ElementAliasMutableDescription
elems[0]lawNThe address of the set contract.
elems[1]lineageYThe material hash of data shared by all objects.

All elements should be provided upon registration, the law element cannot be changed once it is set.

law

The law element is the address of the set contract. For Ethereum-based chains, it can be encoded as bytes32 from an address:

bytes32 law = bytes32(uint160(addr));

linage

The linage element is the material hash representing the shared data for all objects from this set.

This data is typically utilized in the kind contract, and its format—both content type and structure—should conform to what the kind contract expects. The exact design is at the user’s discretion.

For example, in a typical scenario, the material might be required in JSON format and include fields such as:

  • name: The name of the set.
  • description: A brief description of the set.
  • image (optional): A URL or reference to an image representing the set.
  • ... (optional): Additional fields specific to the set.

Operations

Interoperations are not applicable to set objects, but all unary operations are supported and listed below:

OperationFields Affected
transferowner
updatemeta.rev, elems.linage
upgrademeta.rev, meta.kindRev, meta.setRev
touchmeta.rev

Kind

Kinds define the composition, interactions, and asset computations for specific types of objects within the protocol.

All kinds are created from the Set of Kinds, governed by the Kind Registry contract.

Each kind adheres to the Kind of Kind, which specifies the structure, interactions, and asset computations of kind objects themselves.

Several original kinds were established during the initial deployment of the protocol, and many more continue to emerge as users register new kinds.

Kinds are crucial in defining the behavior of objects created by sets. When an object is assigned a specific kind through its set contract, it commits to adhering to the behaviors and rules outlined by that kind.

Creation

Kind objects are created unpon registration, they are initialized as follows:

id

For original kinds, the id field is predefined by constants in the protocol:

uint64 constant ID_KIND_OF_SPACE     = 0;
uint64 constant ID_KIND_OF_SET       = 1;
uint64 constant ID_KIND_OF_KIND      = 2;
uint64 constant ID_KIND_OF_RELATION  = 3;
uint64 constant ID_KIND_OF_TRANSFORM = 4;

For emergent kinds, created dynamically later, their IDs are allocated from a specific range:

uint64 constant ID_KIND_EMERGENT_MIN = 17;
uint64 constant ID_KIND_EMERGENT_MAX = type(uint56).max;

The id is constrained to values no greater than 2^56 - 1 to ensure that the upper 8 bits of the uint64 remain unset.

meta

The meta field is initialized in the following manner, applicable to both original and emergent kinds.

meta.flags      = 0;
meta.rev        = 1;
meta.kindRev    = latestKindOfKind();    // The latest revision of the Kind of Kind
meta.setRev     = latestSetOfKind();     // The latest revision of the Set of Kinds
meta.kind       = ID_KIND_OF_KIND;
meta.set        = ID_SET_OF_KIND;

Since the kind and set objects always point to their latest revisions, kinds created later may have higher values in these fields.

elems

According to the Kind of Kind, a kind object is composed of the following elements:

ElementAliasMutableDescription
elems[0]shapeNSpecifies the element types that compose objects of this kind.
elems[1]codeYMaterial hash of the kind contract responsible for object imaging.
elems[2]geneYMaterial hash of the data shared by all objects of this kind.
elems[3]rels0YRelations supported by destination objects of this kind.
elems[4]rels1YRelations supported by destination objects of this kind.

All elements should be provided upon registration, the shape element cannot be changed once it is set.

shape

The shape element defines the types of elements that compose an object of this kind.

It is interpreted as an array of uint8 values, with any trailing zeroes removed. The length of this array must be between 0 and 16, meaning an object can have no elements or up to a maximum of 16 elements.

All element types must be greater than 0. The following types are supported:

uint8 constant ELEMENT_TYPE_OBJECT            = 1;
uint8 constant ELEMENT_TYPE_INFORMATION       = 2;
uint8 constant ELEMENT_TYPE_VALUE             = 3;
uint8 constant ELEMENT_TYPE_ARTIFACT          = 4;
uint8 constant ELEMENT_TYPE_MATERIAL_GENERAL  = 5;
uint8 constant ELEMENT_TYPE_MATERIAL_JSON     = 6;
uint8 constant ELEMENT_TYPE_MATERIAL_PTABLE   = 7;
uint8 constant ELEMENT_TYPE_MATERIAL_MKTREE   = 8;
uint8 constant ELEMENT_TYPE_MATERIAL_IMAGE    = 9;

code

The code element refers to the material hash of the kind contract.

A kind contract is a WebAssembly (Wasm) bytecode that conforms to specifications defined by the OVM (Object Virtual Machine). These contracts are often compiled from source code written in AssemblyScript using kind-as or in Rust using kind-rs.

gene

The gene element is the material hash representing the shared data for all objects under this kind.

This data is typically utilized in the kind contract, and its format—both content type and structure—should conform to what the kind contract expects. The exact design is at the user’s discretion.

For example, in a typical scenario, the material might be required in JSON format and include fields such as:

  • name: The name of the kind.
  • description: A description of the kind.
  • image (optional): A URL or reference to an image representing the kind.
  • ... (optional): Additional fields specific to the kind.

relsN

The relsN elements define the relations that objects of this kind should support.

These elements provide space for up to 8 relation IDs (uint64). Each relation ID is encoded in big-endian format, written one by one into the relsN elements, filling 32 bytes from left to right. If fewer than 8 relation IDs are specified, the remaining space is filled with zeroes.

Operations

Interoperations are not applicable to set objects, all unary operations are supported and listed below:

OperationFields Affected
transferowner
updatemeta.rev, elems.code, elems.gene, elems.relsN
upgrademeta.rev, meta.kindRev, meta.setRev
touchmeta.rev

Relation

Relations define adjacencies and rules governing how different kinds of objects interact. They specify which kinds of objects, and how many, can be accepted in a relation, as well as the outcomes when objects are connected (related) or disconnected (unrelated) from one another.

All relations are created from a special set called the Set of Relations, which is governed by the OOPS (Object Operating and Positioning System) contract.

Allrelations adhere to the Kind of Relation, which determines the elements that make up a relation object.

Relations play a crucial role in defining kind objects. By listing relation IDs in their fields, kinds declare support for the adjacencies defined by those relations, enabling objects of that kind to interact with others in a structured and regulated way.

Creation

Relation objects are created unpon registration, they are initialized as follows:

id

Relation IDs are allocated from a specific range:

uint64 constant ID_REL_EMERGENT_MIN = 17;
uint64 constant ID_REL_EMERGENT_MAX = type(uint56).max;

The id is constrained to values no greater than 2^56 - 1 to ensure that the upper 8 bits of the uint64 remain unset.

meta

The meta field is initialized in the following manner.

meta.flags   = 0;
meta.rev     = 1;
meta.kindRev = latestKindOfRelation();  // The latest revision of the Kind of Relation
meta.setRev  = latestSetOfRelation();   // The latest revision of the Set of Relations
meta.kind    = ID_KIND_OF_RELATION;
meta.set     = ID_SET_OF_RELATION;

Since the kind and set objects always point to their latest revisions, relations created later may have higher values in these fields.

elems

According to the Kind of Relation, a relation object is composed of the following elements:

ElementAliasMutableDescription
elems[0]descYMateial hash of the metadata for the relation.
elems[1]ruleNRules for handling departure objects when being related or unrelated .
elems[2]adjs0NSpecifies adjacencies supported by the relation.
elems[3]adjs1NSpecifies adjacencies supported by the relation.
elems[4]adjs2NSpecifies adjacencies supported by the relation.
elems[5]adjs3NSpecifies adjacencies supported by the relation.

All elements should be provided upon registration, the rule and adjsN cannot be changed once set.

desc

The desc element is the material hash of the metadata for this relation. It does not play a role in the interactions defined by the relation on the universe chain.

Instead, it's only utilized by the kind contract on the Previous chain. The material should be a JSON object containing fields such as:

  • name: The name of the relation.
  • description: A detailed explanation of the relation.
  • image (optional): A URL or reference to an image representing the relation.

rule

The rule field encoding rules for handling departure objects when they are being related or unrelated.

(To Be Continued)

adjsN

The adjs[0..3] elements collectively define the adjacencies supported by a relation, often referred to as the relation's adjacency specification.

These 4 elements can hold up to 8 adjacency primitives. To ensure a valid adjacency specification, the following rules apply:

  1. Special Kinds:

    • type(uint64).min (0): Represents any, allowing any kind of object not explicitly listed.
    • type(uint64).max (2^64 - 1): Represents total, specifying the maximum number of objects allowed in the relation.
  2. Ordering: Adjacencies must be listed in ascending order of their kind values. If an adjacency with the any kind is present, it must be listed first, and if total is included, it must be listed last.

These 4 elements are filled according to the adjacency primitives in the following manner:

Assuming all adjsN elements are initially set to zero and ordered from left to right, each adjacency is encoded into a uint128 value and sequentially inserted into the array in big-endian format.

Operations

Interoperations are not applicable to relation objects, all unary operations are supported and listed below:

OperationFields Affected
transferowner
updatemeta.rev, elems.desc
upgrademeta.rev, meta.kindRev, meta.setRev
touchmeta.rev

Evolution

Before the singularity, there were no concepts of time, space, elements, objects, or laws—there was nothing.

From the moment of the singularity, time and space began expanding simultaneously, and the first element came into existence.

After a considerable amount of time, during a period referred to as the early stage of the universe, several original elements, objects, and laws were created. These original constructs laid the foundation for the universe's ongoing evolution.

Over time, more elements were discovered, new kinds were built, and new sets were created based on these kinds and elements. From these newly created sets, plain objects emerged.

Under the laws set by governing contracts, objects can mutate, evolve, and interact with one another. They can also traverse spaces, enter different worlds, and even leap beyond the current universe.

The entire universe evolves in a way that is both deterministic and unpredictable.

Singularity

The Singularity marks the inception of a universe, typically represented by the genesis block on its respective chain. A universe's singularity always occurs at time 0:0:0 for that universe. When discussing multiple universes, Coordinated Universal Time (UTC) is used as the standard reference.

Some known universes and their singularities:

  • Universe 1 (Ethereum): Began on July 30, 2015, at 03:26:13 PM UTC.
  • Universe 8453 (Base): Started on June 15, 2023, at 12:35:47 AM UTC.

Before the singularity, there is no concept of time, space, elements, objects, or laws. The singularity represents the moment from which time and space begin to expand, and the first element—typically the native token—comes into existence.

Expansion

The time and space of a universe expand simultaneously from the moment of the singularity.

Time

Time is a series of discrete instants organized into granular units. These units are called blocks, which can be subdivided into smaller intervals called seconds and thirds, providing a hierarchical structure that reflects how time is measured and flows within the universe.

Time can be represented with the following structure:

#![allow(unused)]
fn main() {
struct Time {
    block: u64,
    second: u32,
    third: u32,
}
}

Typically, time is written in the format block:second:third, and time begins at 0:0:0, which marks the start of a universe.

Space

Space is similarly composed of discrete units, referred to as blocks. These blocks are isolated from one another, and the distances or relationships between them are not currently understood. Collectively, these blocks make up the block space, often simply called the space.

There is also a special kind of space called the void space, which fills the gaps between blocks. The void space was formed at the singularity and is considered a unique block—block 0. As time progresses and space expands, each newly created block is assigned a number corresponding to the block element of its creation time.

The overall shape of the block space defines the shape of the universe. According to the Growing Block Theory1, it is hypothesized that the block space has a spiral shape, representing the continuous outward expansion of the universe with each new block. However, the precise mathematical structure of this space remains undefined.


1

Fictionalized according to Growing Block Universe.

Original Constructs

After a considerable passage of time, a brief yet pivotal period saw the emergence of several original constructs that shaped the foundation of the universe. This period is often referred to as the early stage of the universe.

Elements

The original elements that emerged include:

  • Values: Representing the native tokens within the universe.
  • Artifacts: The protocol’s original NFTs (OG NFTs).
  • Materials: Resources related to original elements and objects.

Kinds

The original kind objects that define key constructs in the universe:

  • The Kind of Set: Defines the structure of all sets.
  • The Kind of Kind: Defines the structure of all kinds.
  • The Kind of Relation: Defines the structure of all relations.
  • The Kind of Transform: Defines the structure of all transforms.

Sets

The original set objects that serve as the source for other constructs:

  • The Set of Sets: The foundation from which all sets are created.
  • The Set of Kinds: The foundation from which all kinds are created.
  • The Set of Relations: The foundation from which all relations are created.
  • The Set of Transforms: The foundation from which all transforms are created.

Laws

The original governing laws that maintain order:

  • Element Registry: Governs the registration and organization of elements.
  • Set Registry: Governs the registration and organization of sets.
  • Kind Registry: Governs the registration and organization of kinds.
  • OOPS (Object Operating and Positioning System): Manages the registration of relations, transforms, and spaces, and governs object interaction and positioning.

Emergent Constructs

As the universe evolves, new elements, kinds, and sets emerge, all governed by the foundational original laws established in the early stages of its development.

Discovery of New Elements

Elements are needed by objects, without them objects can not be constructed.

In order for elements to be used by objects, they must be registered in the Element Registry—this process is referred to as their element discovery.

Information elements do not require prior registration. They can be used directly as needed. Currently, there is no established method for registering materials. It is anticipated that, as the need arises, a method for registering and authorizing materials will be implemented.

Values

To register a value element in the registry.

function registerValue(TokenStandard std, address addr, bytes32 data)
    external
    returns (uint64);

Artifacts

To register a artifact element in the registry.

function registerArtifact(TokenStandard std, address addr, bytes32 data, uint64 idBeg, uint64 idEnd)
    external
    returns (uint64);

Emergence of New Kinds

Kinds serve as a type system for tokens, functioning as abstractions that allow real-world concepts to be represented within the crypto space. They simplify the process of creating interactive tokens, reducing complexity for developers. Essentially, kinds are like "species" within a universe, making the system more versatile.

To encourage reusability and prevent misuse, kinds are created with a cost. This approach incentivizes users to utilize existing kinds rather than continually creating new ones.

A fundamental aspect of the Previous chain's tokenomics is that kind owners are rewarded economically when their kinds are utilized. The system tracks which kinds are being employed by various objects, ensuring transparent and fair rewards for their owners.

To register a kind in the Kind Registry:

function register(ElementType[] memory shape, bytes32 code, bytes32 gene, uint64[] memory rels)
    external
    returns (uint64);

Formation of New Sets

By leveraging elements, kinds, relations, and transforms, the creation of sets has become significantly more streamlined. These abstractions distribute the workload traditionally managed by teams to individuals across the entire network, all on-chain.

This not only simplifies the creation process and facilitates efficient on-chain collaboration, but also lowers the overall investment required.

To prevent spam, the creation of new sets involves a cost.

To register a set in the Set Registry:

function register(address law, bytes32 lineage)
    external
    returns (uint64);

Development of Objects

The lifecycle of objects is managed by the set contract associated with the set object. Function calls are made to this contract to guide the object’s development.

Creation

Objects can be created from sets.

The method for creating new objects is determined by the set contract. A recommended function signature is:

function create(uint64 id, bytes memory data) external returns (uint64);

In this function:

  • The id can be 0, meaning no specific ID is required, or non-zero if a specific ID is desired.
  • The data parameter can be empty or contain additional information, which is interpreted by the set contract according to its requirements.

Update

Objects have the ability to change through a call to the update function:

function update(uint64 id, bytes memory data) external returns (Meta memory);

A set contract may choose not to implement the function, or it can revert the transaction, effectively disabling the ability to update the object.

Upgrade

Objects have the ability to evolve by applying updates from their kind or set objects. This process is initiated through a call to the upgrade function:

function upgrade(uint64 id, uint32 kindRev, uint32 setRev)
    external
    returns (Meta memory);

It's important to note that updates to kind or set objects do not automatically trigger an upgrade. The upgrade only occurs when initiated by the object's owner, ensuring that the control over the object remains with its owner.

For unminted objects, the set contract can determine whether to adopt the most recent version of the kind or set object or a specific vision, allowing flexibility in how upgrades are managed.

A set contract may choose not to implement the function, or it can revert the transaction, effectively disabling the ability to upgrade the object.

Interactions

Operations involving two or more objects are generally referred to as interactions. These are actually interoperations that can be registered and executed through the OOPS contract.

Research on transforms is ongoing, and they will be detailed in future updates.

New Relations

To register a new relation:

function registerRelation(bytes32 desc, RelationRule memory rule, uint128[] memory adjs)
    external
    returns (uint64);

Relating Objects

To relate a dependent object to a destination object:

function relate(uint256 dep, uint128 dest) external;

To relate multiple dependent objects to a destination object:

function relate(uint256[] memory deps, uint128 dest) external;

Unrelating Objects

To unrelate a dependent object from a destination object:

function unrelate(uint256 dep, uint128 dest) external;

To unrelate multiple dependent objects from a destination object:

function unrelate(uint256[] memory deps, uint256 dest) external;

Exploration

Spaces can be claimed by users if they are unoccupied.

The owner of a space can set rules to determine what kinds of objects can move into the space, similar to how relations are formed between objects. This is why move is also considered a type of interoperation.

Portals and wormholes can be built within a space, effectively turning the entire space into an entry point to another world or universe.

Space registration and related operations are governed by the OOPS contract.

Claim Spaces

To register a new space at a specific block:

function registerSpace(uint64 block, bytes32 desc) external;

To move an object to a new position:

function move(uint256 obj, uint128 pos) external;

To move multiple objects to a new position:

function move(uint256[] memory objs, uint128 pos) external;

Discovering New Worlds

TBD

Verse Jumping

TBD

Imaging

Key information constantly transmitted in the air, such as chain committed, chain reorganized, and chain reverted, are referred to as radiation. Radiation is detected, filtered, and extracted by probes and transformed into signals, which are then relayed to the Previous chain.

A process called object imaging is carried out by the Object Virtual Machine (OVM) on the Previous chain. This process calculates assets for the new revision of an object, making them accessible to apps and users via satellites.

Radiation

Information that is constantly transmitted in the air is referred to as radiation. By detecting and analyzing these radiations, builders of probes discovered that they tend to approach some form of consensus, and can be categorized into three types:

  1. Chain Committed: Represents confirmed events that have been accepted into the universe chain. These events form the foundation for more structured data, such as transactions or receipts. Committed radiations signal firm decisions and mark a point of finality in the chain.

  2. Chain Reorganized: Indicates the reorganization of a chain, where previous states are reshuffled to accommodate new events. This alters the chain's structure but doesn't fully revert prior actions, making it a temporary shift rather than a complete undoing.

  3. Chain Reverted: Refers to a full rollback of part of the chain. Events and transactions are effectively erased as though they never happened, signaling a complete reversal and restoration of the chain to an earlier state.

From these fundamental types of radiation, builders have been able to extract more specific and detailed signals. For instance, Chain Committed radiation often contain embedded commitments to structured data, such as transactions and receipts. By delving deeper into these layers, a variety of signals have been identified, enriching the understanding of the universe's activities.

Signals

Signals are events extracted from radiation emitted by universes within the protocol.

Below is a list of signal names with brief explanations. They are categorized for readability, and further details can be found in later chapters.

  • UniverseExpanded: Indicates the expansion of a universe due to chain confirmations, representing the growth of space and time within that universe.
  • UniverseRewound: Signals the rollback of a universe due to chain reverts or reorganizations.
  • UniverseShifted: Reflects significant changes in the constants or laws that govern the universe.
  • ValueDiscovered: A new fungible token is identified.
  • ArtifactDiscovered: A new non-fungible token is uncovered.
  • SetCreated: Indicates the establishment of a new set.
  • KindCreated: Signals the creation of a new kind.
  • RelationCreated: A new relation is defined between objects.
  • TransformCreated: Defines a new transformation rule.
  • SpaceClaimed: A space is claimed within the universe.

Lifecycle signals:

  • Created: A new object is minted.
  • Updated: The object’s state is changed, leading to a new revision.
  • Upgraded: The object's revision is incremented due to its kind and/or set is upgraded.
  • Touched: The object’s revision is incremented without altering its core properties.
  • Destroyed: The object is permanently removed.

Ownership, positioning, and relations:

  • Transferred: The object’s ownership is transferred.
  • Moved: The object’s position is changed within a space.
  • Related: The object forms a connection with another object.
  • Unrelated: The object is disconnected from another object.

World exploration:

  • Entered: The object enters a new world.
  • Left: The object exits a world.

Verse-jumping:

  • Jumped: The object moves to a new universe.
  • Dropped: The object arrives in the current universe from an outer-verse.

Imaging

Most lifecycle and relation-related signals cause a revision bump of the object, triggering the recalculation of its assets for the new revision. This process, known as object imaging (or simply imaging), is handled by the OVM on the Previous chain. Imaging is done by executing WebAssembly (Wasm) code defined in the object's kind contract.

Input/Output

Two key inputs are used to determine the code and data required for execution:

  • oid: The object’s unique identifier.
  • rev: The revision of the object.

The output is a vector, with each element consisting of:

  • selector: Identifies the specific asset of the object.
  • material: Represents the asset content of the object at the specified revision.

Selectors are extracted from the custom section (according to OVM specification) of the Wasm bytecode and correspond to public asset functions defined in the kind contract source code.

Execution

1. Loading the Kind Contract

The first step is loading the kind contract from chain storage. The code element of the kind object is used to retrieve the Wasm bytecode.

Pseudocode for retrieving the kind contract:

#![allow(unused)]
fn main() {
let kind_oid: Oid = oid.kind_oid();
let meta: Meta = storage.get_meta(oid, rev);
let kind_elems: Vec<Bytes32> = storage.get_object_data(kind_oid, meta.kind_rev);
let kind_code: Bytes32 = kind_elems[1];
let code_material: Material = storage.get_material(kind_code);
let code: Bytes = code_material.content;
}

2. Linking with Host Functions

The OVM specification requires a set of host functions to be available for the Wasm contract at runtime. These functions are critical for interacting with the blockchain state and for processing various types of materials.

Host functions handle materials such as:

  • 2D images
  • JSON data
  • Merkle trees
  • Plain tables

Other host functions provide access to object-related information, such as:

  • Listing related objects: Helps retrieve the objects linked to the current object being processed.
  • Fetching asset materials of related objects: Enables access to the assets of linked objects, crucial for interoperability.

New host functions can be added as the specification evolves. All host functions are designed to ensure determinism, which is essential for the security and verifiability of dynamic NFTs in a decentralized context.

3. Initializing Memory

The elements of the object are retrieved from chain storage and used to initialize the linear memory of the Wasm instance. Elements data is always starting from a fixed offset.

Pseudocode for loading the elements:

#![allow(unused)]
fn main() {
let elems: Vec<Bytes32> = storage.get_object_data(oid, rev);
}

4. Invoking the Entry Function

The only function exported from a kind contract is the entry function. It is auto-generated by compilers to simplify the programming process. A selector is used to specify which asset function to call for each execution.

Pseudocode for entry function invacations:

#![allow(unused)]
fn main() {
let entry = instance.get_typed_func::<(u32, u32), Option<Rooted<ExternRef>>>(&mut store, "entry")?;
let mut result = Vec::<ObjectAsset>::new();
for sel in selectors {
	let r = entry.call(&mut store, (OBJ_OFFSET, sel))?;
	let oa = Self::to_asset(sel, er, store)?;
	result.push(oa);
}
}

In theory, all asset functions need to be called to compute a new revision of an object, but the OVM can optimize this to only recalculate assets when necessary.

State Transition

Once execution succeeds, the generated assets are committed to chain storage, and a record of asset pointers (hashes to asset materials) is added to the object’s state for that revision. If the execution fails, no asset material is stored, and a record marking the object as malformed is saved.

This ensures that the assets of objects are accessible via satellites.

Accessing

Object assets can be accessed using PRE URIs and retrieved via satellites.

PRE URI

A PRE URI (Uniform Resource Identifier) is used to locate and access a specific asset of an object at a particular revision. The format for the URI is:

pre://{oid}/{rev}/{sel}
  • oid: The unique identifier of the object, in dot-decimal format.
  • rev: The object's revision number.
  • sel: Selector to specify the asset type.

Alternatively, materials or object assets can be retrieved via a hash-based URI:

pre://{universe}/{hash}
  • universe: The universe ID where the material's preimage is known.
  • hash: The hexadecimal hash of the material or asset.

HTTP Gateway URL

For browsers or legacy systems that don’t natively support PRE URIs, object assets can be accessed using HTTP gateways:

https://preimage.link/{oid}/{rev}/{sel}

or through the hash-based URL:

https://preimage.link/{universe}/{hash}

These URLs allow assets to be easily viewed or downloaded via a web browser.

By leveraging satellites and gateways like preimage.link, the protocol ensures transparent, verifiable, and accessible object assets, whether accessed through decentralized command-line interfaces or web platforms.

Element Registry

Element registration and management.

Functions

registerValue

Registers a new value element in the registry.

function registerValue(TokenStandard std, address addr, bytes32 data) external returns (uint64);

Parameters

NameTypeDescription
stdTokenStandardThe token standard (e.g., ERC20, ERC777).
addraddressThe address of the token contract.
databytes32The material hash related to the token.

Returns

NameTypeDescription
<none>uint64The ID of the newly registered value element.

updateValue

Updates the material data of an existing value element.

function updateValue(uint64 token, bytes32 data) external;

Parameters

NameTypeDescription
tokenuint64The ID of the token element being updated.
databytes32New material hash for the token element.

registerArtifact

Registers a new artifact element in the registry.

function registerArtifact(TokenStandard std, address addr, bytes32 data, uint64 idBeg, uint64 idEnd)
    external
    returns (uint64);

Parameters

NameTypeDescription
stdTokenStandardThe token standard (e.g., ERC721, ERC1155).
addraddressThe address of the token contract.
databytes32The material hash related to the token.
idBeguint64The beginning ID of the token.
idEnduint64The ending ID of the token.

Returns

NameTypeDescription
<none>uint64The ID of the newly registered artifact element.

updateArtifact

Updates the material data of an existing artifact element.

function updateArtifact(uint64 token, bytes32 data) external;

Parameters

NameTypeDescription
tokenuint64The ID of the token element being updated.
databytes32New material hash for the token element.

Events

ValueRegistered

Emitted when a new value element is registered.

event ValueRegistered(uint64 token, TokenStandard std, address addr, bytes32 data, address admin);

Parameters

NameTypeDescription
tokenuint64The ID of the newly registered value element.
stdTokenStandardThe token standard (e.g., ERC20, ERC777).
addraddressThe address of the token contract.
databytes32The material hash related to the token.
adminaddressThe address of the administrator.

ValueUpdated

Emitted when a value element is updated.

event ValueUpdated(uint64 token, bytes32 data);

Parameters

NameTypeDescription
tokenuint64The ID of the value element being updated.
databytes32New material hash for the token.

ValueTransferred

Emitted when administrator of a value element is changed.

event ValueTransferred(uint64 token, address from, address to);

Parameters

NameTypeDescription
tokenuint64The ID of the value element.
fromaddressThe address of the current administrator.
toaddressThe address of the new administrator.

ArtifactRegistered

Emitted when a new artifact element is registered.

event ArtifactRegistered(
    uint64 token, TokenStandard std, address addr, bytes32 data, uint64 idBeg, uint64 idEnd, address admin
);

Parameters

NameTypeDescription
tokenuint64The ID of the newly registered artifact element.
stdTokenStandardThe token standard (e.g., ERC721, ERC1155).
addraddressThe address of the token contract.
databytes32The material hash related to the token.
idBeguint64The beginning ID of the token.
idEnduint64The ending ID of the token.
adminaddressThe address of the administrator.

ArtifactUpdated

Emitted when an artifact element is updated.

event ArtifactUpdated(uint64 token, bytes32 data);

Parameters

NameTypeDescription
tokenuint64The ID of the token being updated.
databytes32New material hash for the token.

ArtifactTransferred

Emitted when administrator of an artifact element is changed.

event ArtifactTransferred(uint64 token, address from, address to);

Parameters

NameTypeDescription
tokenuint64The ID of the artifact element.
fromaddressThe address of the current administrator.
toaddressThe address of the new administrator.

Set Registry

Set registration and management.

Functions

register

Registers a new set in the registry.

function register(address impl, bytes32 data) external returns (uint64);

Parameters

NameTypeDescription
impladdressThe address of the set contract.
databytes32The material hash of the set's data.

Returns

NameTypeDescription
<none>uint64The ID of the newly registered set.

update

Updates the metadata and description of a set.

function update(uint64 id, bytes32 data) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the set to update.
databytes32The updated metadata or description hash.

Returns

NameTypeDescription
<none>MetaThe updated metadata of the set.

upgrade

Upgrades a set's kind and/or set to a newer revision.

function upgrade(uint64 id, uint32 kindRev, uint32 setRev) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the set to upgrade.
kindRevuint32The newer revision of the set's kind object (0 indicates no upgrade).
setRevuint32The newer revision of the set's set object (0 indicates no upgrade).

Returns

NameTypeDescription
<none>MetaThe metadata of the set after the upgrade.

touch

Touches the set to trigger a revision bump.

function touch(uint64 id) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the set.

Returns

NameTypeDescription
<none>MetaThe metadata of the set after touch.

transfer

Transfers ownership of a set to a new address.

function transfer(uint64 id, address to) external;

Parameters

NameTypeDescription
iduint64The ID of the set.
toaddressThe address of the new owner.

ownerOf

Returns the owner of a specific set.

function ownerOf(uint64 id) external view returns (address);

Parameters

NameTypeDescription
iduint64The ID of the set.

Returns

NameTypeDescription
<none>addressThe address of the set owner.

implOf

Returns the implementation address of a set.

function implOf(uint64 id) external view returns (address);

Parameters

NameTypeDescription
iduint64The ID of the set.

Returns

NameTypeDescription
<none>addressThe address of the set's implementation.

metaAt

Returns the metadata of a set at a specific revision.

function metaAt(uint64 id, uint32 rev) external view returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the set.
revuint32The revision number (0 indicates the latest revision).

Returns

NameTypeDescription
<none>MetaThe metadata of the set at the specified revision.

stateAt

Returns the elements of a set at a specific revision.

function stateAt(uint64 id, uint32 rev) external view returns (bytes32[] memory);

Parameters

NameTypeDescription
iduint64The ID of the set.
revuint32The revision number (0 indicates the latest revision).

Returns

NameTypeDescription
<none>bytes32[]The elements of the set at the specified revision.

revAt

Checks if a revision of a set is valid.

function revAt(uint64 id, uint32 rev) external view returns (uint32);

Parameters

NameTypeDescription
iduint64The ID of the set.
revuint32The revision number to check (0 indicates the latest revision).

Returns

NameTypeDescription
<none>uint32The valid revision number, or 0 if the revision is invalid.

Events

SetRegistered

Emitted when a new set is registered.

event SetRegistered(uint64 id, Meta meta, address impl, bytes32 data, address owner);

Parameters

NameTypeDescription
iduint64The ID of the set.
metaMetaThe intial metadata of the set.
impladdressThe address of the set's contract.
databytes32The material hash of the set's data
owneraddressThe address of the set's owner.

SetUpdated

Emitted when a set is updated.

event SetUpdated(uint64 id, Meta meta, bytes32 data);

Parameters

NameTypeDescription
iduint64The ID of the set.
metaMetaUpdated metadata of the set.
databytes32Updated material hash of the set's data.

SetUpgraded

Emitted when a set is upgraded.

event SetUpgraded(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The unique ID of the set.
metaMetaThe metadata of the set after upgrade.

SetTouched

Emitted when a set is touched.

event SetTouched(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The ID of the set.
metaMetaThe metadata of the set after touch.

SetTransferred

Emitted when ownership of a set is transferred.

event SetTransferred(uint64 id, address from, address to);

Parameters

NameTypeDescription
iduint64The ID of the set.
fromaddressThe address of the previous owner.
toaddressThe address of the new owner.

Kind Registry

Kind registration and management.

Functions

register

Registers a new kind with the specified parameters.

function register(ElementType[] memory stateSpec, bytes32 code, bytes32 data, uint64[] memory relSpec)
    external
    returns (uint64);

Parameters

NameTypeDescription
stateSpecElementType[]Specification of the elements that define the object's state.
codebytes32The material hash of the kind's code.
databytes32The material hash of the kind's data.
relSpecuint64[]List of relations supported by this kind.

Returns

NameTypeDescription
<none>uint64The ID of the newly registered kind.

update

Updates the code, data of an existing kind.

function update(uint64 id, bytes32 code, bytes32 data) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the kind to be updated.
codebytes32The new material hash representing the kind's code. A zero value indicates no change.
databytes32The new material hash representing the kind's data. A zero value indicates no change.

Returns

NameTypeDescription
<none>MetaThe updated metadata for the kind.

update

Updates the code, data, and relations of an existing kind.

function update(uint64 id, bytes32 code, bytes32 data, uint64[] memory relSpec) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the kind to update.
codebytes32The new material hash representing the kind's code. A zero value indicates no change.
databytes32The new material hash representing the kind's data. A zero value indicates no change.
relSpecuint64[]The updated list of relations for the kind.

Returns

NameTypeDescription
<none>MetaThe updated metadata of the kind.

upgrade

Upgrades a kind's kind and/or set to a newer revision.

function upgrade(uint64 id, uint32 kindRev, uint32 setRev) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the kind to upgrade.
kindRevuint32The newer revision of the kind's kind object (0 indicates no upgrade).
setRevuint32The newer revision of the kind's set object (0 indicates no upgrade).

Returns

NameTypeDescription
<none>MetaThe metadata of the kind after the upgrade.

touch

Increases the revision of the kind without any state changes.

function touch(uint64 id) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the kind to touch.

Returns

NameTypeDescription
<none>MetaThe updated metadata of the kind.

transfer

Transfers ownership of a kind to another address.

function transfer(uint64 id, address to) external;

Parameters

NameTypeDescription
iduint64The ID of the kind to transfer.
toaddressThe address of the new owner.

ownerOf

Returns the owner of a kind.

function ownerOf(uint64 id) external view returns (address);

Parameters

NameTypeDescription
iduint64The ID of the kind.

Returns

NameTypeDescription
<none>addressThe address of the owner.

stateSpecAt

Retrieves the state specification of a kind at a given revision.

function stateSpecAt(uint64 id, uint32 rev) external view returns (ElementType[] memory);

Parameters

NameTypeDescription
iduint64The ID of the kind.
revuint32The specific revision number. A zero value returns the latest revision.

Returns

NameTypeDescription
<none>ElementType[]The state specification of the kind.

codeAt

Retrieves the code hash of a kind at a given revision.

function codeAt(uint64 id, uint32 rev) external view returns (bytes32);

Parameters

NameTypeDescription
iduint64The ID of the kind.
revuint32The specific revision number. A zero value returns the latest revision.

Returns

NameTypeDescription
<none>bytes32The code hash of the kind.

relSpecAt

Retrieves the relations supported by a kind at a given revision.

function relSpecAt(uint64 id, uint32 rev) external view returns (uint64[] memory);

Parameters

NameTypeDescription
iduint64The ID of the kind.
revuint32The specific revision number. A zero value returns the latest revision.

Returns

NameTypeDescription
<none>uint64[]The supported relations.

metaAt

Returns the metadata of a kind at a specific revision.

function metaAt(uint64 id, uint32 rev) external view returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the kind.
revuint32The revision number. A zero value returns the latest revision.

Returns

NameTypeDescription
<none>MetaThe metadata of the kind.

stateAt

Retrieves the elements of a kind at a specific revision.

function stateAt(uint64 id, uint32 rev) external view returns (bytes32[] memory);

Parameters

NameTypeDescription
iduint64The ID of the kind.
revuint32The revision number. A zero value returns the latest revision.

Returns

NameTypeDescription
<none>bytes32[]The elements of the kind at the specified revision.

revAt

Checks if a revision of a kind is valid.

function revAt(uint64 id, uint32 rev) external view returns (uint32);

Parameters

NameTypeDescription
iduint64The unique identifier of the kind.
revuint32The specific revision to check, with zero indicating the latest revision.

Returns

NameTypeDescription
<none>uint32The revision number requested. A zero return value means the revision is invalid.

Events

KindRegistered

Emitted when a new kind is registered in the registry.

event KindRegistered(
    uint64 id, Meta meta, ElementType[] stateSpec, bytes32 code, bytes32 data, uint64[] relSpec, address owner
);

Parameters

NameTypeDescription
iduint64The ID of the newly registered kind.
metaMetaMetadata of the registered kind.
stateSpecElementType[]The element specification of objects belonging to this kind.
codebytes32The material hash of the kind's code.
databytes32The material hash of the kind's data.
relSpecuint64[]List of relations supported by this kind.
owneraddressThe address that owns the registered kind.

KindUpdated

Emitted when a kind is updated.

event KindUpdated(uint64 id, Meta meta, uint64[] relSpec, bytes32 code, bytes32 data);

Parameters

NameTypeDescription
iduint64The ID of the updated kind.
metaMetaUpdated metadata of the kind.
relSpecuint64[]Updated list of relations associated with the kind.
codebytes32Updated material hash of the kind's code.
databytes32Updated material hash of the kind's data.

KindUpgraded

Emitted when a kind is upgraded.

event KindUpgraded(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The ID of the upgraded kind.
metaMetaUpdated metadata of the upgraded kind.

KindTouched

Emitted when a kind's revision is bumped without state change.

event KindTouched(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The ID of the kind.
metaMetaMetadata of the touched kind.

KindTransferred

Emitted when ownership of a kind is transferred.

event KindTransferred(uint64 id, address from, address to);

Parameters

NameTypeDescription
iduint64The ID of the kind being transferred.
fromaddressThe current owner of the kind.
toaddressThe new owner of the kind.

OOPS

OOPS (Object Operating and Positioning System) is the contract responsible for handling the registration and management of relations, transforms, and spaces, while also overseeing object interactions and positioning within the protocol.

Functions

registerRelation

Registers a new relation

function registerRelation(bytes32 desc, RelationRule memory rule, uint64[] memory adjSpec) external returns (uint64);

Parameters

NameTypeDescription
descbytes32The description of the relation
ruleRelationRuleThe rule defining the relation's behavior
adjSpecuint64[]The adjacency specification for the relation

Returns

NameTypeDescription
<none>uint64The ID of the newly registered relation

updateRelation

Updates an existing relation

function updateRelation(uint64 rel, bytes32 desc) external;

Parameters

NameTypeDescription
reluint64The ID of the relation to update
descbytes32The new description of the relation

transferRelation

Transfers ownership of a relation to another address

function transferRelation(uint64 rel, address to) external;

Parameters

NameTypeDescription
reluint64The ID of the relation
toaddressThe address to transfer ownership to

registerSpace

Registers a new space at a specific block

function registerSpace(uint64 block, bytes32 desc) external;

Parameters

NameTypeDescription
blockuint64The block number of the space
descbytes32The description of the space

updateSpace

Updates an existing space

function updateSpace(uint64 block, bytes32 desc, uint64[] memory rels) external;

Parameters

NameTypeDescription
blockuint64The block number of the space
descbytes32The new description of the space
relsuint64[]Updated relations in the space

transferSpace

Transfers ownership of a space to another address

function transferSpace(uint64 block, address to) external;

Parameters

NameTypeDescription
blockuint64The block number of the space
toaddressThe address to transfer ownership to

relate

Relates a dependent object to a destination object

function relate(uint256 dep, uint128 dest) external;

Parameters

NameTypeDescription
depuint256The ID of the dependent object
destuint128The ID of the destination object

relate

Relates multiple dependent objects to a destination object

function relate(uint256[] memory deps, uint128 dest) external;

Parameters

NameTypeDescription
depsuint256[]Array of dependent object IDs
destuint128The ID of the destination object

unrelate

Unrelates a dependent object from a destination object

function unrelate(uint256 dep, uint128 dest) external;

Parameters

NameTypeDescription
depuint256The ID of the dependent object
destuint128The ID of the destination object

unrelate

Unrelates multiple dependent objects from a destination object

function unrelate(uint256[] memory deps, uint256 dest) external;

Parameters

NameTypeDescription
depsuint256[]Array of dependent object IDs
destuint256The ID of the destination object

move

Moves an object to a new position

function move(uint256 obj, uint128 pos) external;

Parameters

NameTypeDescription
objuint256The ID of the object
posuint128The new position of the object

move

Moves multiple objects to a new position

function move(uint256[] memory objs, uint128 pos) external;

Parameters

NameTypeDescription
objsuint256[]Array of object IDs
posuint128The new position of the objects

Events

RelationRegistered

Emitted when a new relation is registered

event RelationRegistered(uint64 rel, RelationRule rule, uint64[] adjSpec, bytes32 desc, address owner);

Parameters

NameTypeDescription
reluint64The ID of the registered relation
ruleRelationRuleThe rule defining the relation's behavior
adjSpecuint64[]Specifies adjacencies or dependencies for the relation
descbytes32The description of the relation
owneraddressThe owner of the relation

RelationUpdated

Emitted when an existing relation is updated

event RelationUpdated(uint64 rel, bytes32 desc);

Parameters

NameTypeDescription
reluint64The ID of the updated relation
descbytes32The updated description of the relation

RelationTransferred

Emitted when a relation's ownership is transferred

event RelationTransferred(uint64 rel, address from, address to);

Parameters

NameTypeDescription
reluint64The ID of the transferred relation
fromaddressThe current owner of the relation
toaddressThe new owner of the relation

SpaceRegistered

Emitted when a new space is registered

event SpaceRegistered(uint64 block, bytes32 desc, address owner);

Parameters

NameTypeDescription
blockuint64The block number where the space is registered
descbytes32The description of the space
owneraddressThe owner of the space

SpaceUpdated

Emitted when a space's details are updated

event SpaceUpdated(uint64 block, bytes32 desc, uint64[] rels);

Parameters

NameTypeDescription
blockuint64The block number of the space
descbytes32The updated description of the space
relsuint64[]The updated relations in the space

SpaceTransferred

Emitted when ownership of a space is transferred

event SpaceTransferred(uint64 block, address from, address to);

Parameters

NameTypeDescription
blockuint64The block number of the space
fromaddressThe current owner of the space
toaddressThe new owner of the space

Emitted when an object is related to another object

event Related(uint256 dep, uint128 dest, uint32 rev);

Parameters

NameTypeDescription
depuint256The ID of the dependent object
destuint128The ID of the destination object
revuint32The revision number of the relation

Emitted when multiple objects are related to a destination object

event Related(uint256[] deps, uint128 dest, uint32 rev);

Parameters

NameTypeDescription
depsuint256[]Array of dependent object IDs
destuint128The ID of the destination object
revuint32The revision number of the relation

Unrelated

Emitted when an object is unrelated (disconnected) from another object

event Unrelated(uint256 dep, uint128 dest, uint32 rev);

Parameters

NameTypeDescription
depuint256The ID of the dependent object
destuint128The ID of the destination object
revuint32The revision number of the relation

Unrelated

Emitted when multiple objects are unrelated from a destination object

event Unrelated(uint256[] deps, uint128 dest, uint32 rev);

Parameters

NameTypeDescription
depsuint256[]Array of dependent object IDs
destuint128The ID of the destination object
revuint32The revision number of the relation

Moved

Emitted when the position of an object is changed

event Moved(uint256 obj, uint128 pos);

Parameters

NameTypeDescription
objuint256The ID of the object being moved
posuint128The new position of the object

Moved

Emitted when multiple objects are moved to a new position

event Moved(uint256[] objs, uint128 pos);

Parameters

NameTypeDescription
objsuint256[]Array of object IDs being moved
posuint128The new position of the objects

Structs

RelationRule

Describes the rules of a relation between objects.

struct RelationRule {
    uint8 ownerOnForm;
    uint8 posOnForm;
    uint8 connOnForm;
    uint8 ownerOnTerm;
    uint8 posOnTerm;
    uint8 connOnTerm;
}

Set Interface

Interface a user-created set must implement.

interface ISet {
    // events
    event Created(uint64 id, Meta meta, bytes32[] state, address owner);
    event Updated(uint64 id, Meta meta, bytes32[] state);
    event Upgraded(uint64 id, Meta meta);
    event Touched(uint64 id, Meta meta);
    event Destroyed(uint64 id, Meta meta);
    event Transferred(uint64 id, address from, address to);

    // write functions
    function update(uint64 id, bytes32[] memory state) external returns (Meta memory);
    function upgrade(uint64 id, uint32 kindRev, uint32 setRev) external returns (Meta memory);
    function touch(uint64 id) external returns (Meta memory);
    function transfer(uint64 id, address to) external;

    // view functions
    function ownerOf(uint64 id) external view returns (address);
    function metaAt(uint64 id, uint32 rev) external view returns (Meta memory);
    function stateAt(uint64 id, uint32 rev) external view returns (bytes32[] memory);
    function revAt(uint64 id, uint32 rev) external view returns (uint32);
}

Functions

update

Updates the elements of an object.

function update(uint64 id, bytes32[] memory state) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the object to update.
statebytes32[]The new elements of the object.

Returns

NameTypeDescription
<none>MetaThe updated metadata of the object.

upgrade

Upgrades the kind and/or set of an object to a newer revision.

function upgrade(uint64 id, uint32 kindRev, uint32 setRev) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the object to upgrade.
kindRevuint32The new revision of the kind object (0 indicates no upgrade).
setRevuint32The new revision of the set object (0 indicates no upgrade).

Returns

NameTypeDescription
<none>MetaThe metadata of the object after the upgrade.

touch

Touches an object to trigger a revision bump.

function touch(uint64 id) external returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the object to touch.

Returns

NameTypeDescription
<none>MetaThe metadata of the object after the touch.

transfer

Transfers the ownership of an object to a new address.

function transfer(uint64 id, address to) external;

Parameters

NameTypeDescription
iduint64The ID of the object to transfer.
toaddressThe address to transfer the ownership to.

ownerOf

Returns the owner of an object.

function ownerOf(uint64 id) external view returns (address);

Parameters

NameTypeDescription
iduint64The ID of the object.

Returns

NameTypeDescription
<none>addressThe address of the object's owner.

metaAt

Returns the metadata of an object at a particular revision.

function metaAt(uint64 id, uint32 rev) external view returns (Meta memory);

Parameters

NameTypeDescription
iduint64The ID of the object.
revuint32The revision number. A zero value indicates the latest revision.

Returns

NameTypeDescription
<none>MetaThe metadata of the object.

stateAt

Returns the elements of an object at a particular revision.

function stateAt(uint64 id, uint32 rev) external view returns (bytes32[] memory);

Parameters

NameTypeDescription
iduint64The ID of the object.
revuint32The revision number. A zero value indicates the latest revision.

Returns

NameTypeDescription
<none>bytes32[]The elements of the object.

revAt

Checks if a revision of an object is valid.

function revAt(uint64 id, uint32 rev) external view returns (uint32);

Parameters

NameTypeDescription
iduint64The ID of the object.
revuint32The specific revision. A zero value indicates the latest revision.

Returns

NameTypeDescription
<none>uint32The revision number requested. Zero indicates an invalid revision.

Events

Created

Emitted when a new object is created within a set.

event Created(uint64 id, Meta meta, bytes32[] state, address owner);

Parameters

NameTypeDescription
iduint64The ID of the object.
metaMetaThe metadata of the object.
statebytes32[]The elements of the object.
owneraddressThe address of the object's owner.

Updated

Emitted when an object is updated.

event Updated(uint64 id, Meta meta, bytes32[] state);

Parameters

NameTypeDescription
iduint64The ID of the object.
metaMetaThe updated metadata of the object.
statebytes32[]The updated elements of the object.

Upgraded

Emitted when an object is upgraded.

event Upgraded(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The ID of the object.
metaMetaThe updated metadata of the object after the upgrade.

Touched

Emitted when an object is touched.

event Touched(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The ID of the object.
metaMetaThe metadata of the object.

Destroyed

Emitted when an object is destroyed.

event Destroyed(uint64 id, Meta meta);

Parameters

NameTypeDescription
iduint64The ID of the object.
metaMetaThe metadata of the object before destruction.

Transferred

Emitted when the ownership of an object is transferred.

event Transferred(uint64 id, address from, address to);

Parameters

NameTypeDescription
iduint64The ID of the object.
fromaddressThe address of the current owner.
toaddressThe address of the new owner.

Profile Objects

Wearables

Blog 3.0

Generative Art

Algorithmic Living Objects

AI-Powered Living Objects

Game Items

Game Characters

Worlds

Contributing

Everything theory is in its early stages, and there are many ways to get involved. Your contribution help shape the future of the protocol.

Read & Share

The simplest way to contribute is by reading this document and sharing it with friends, colleagues, or communities who might be interested in the theory.

If these ideas excite you, consider contributing to help build the protocol.

Design

If you have visions about the future of NFTs or crypto, are familiar with concepts from Greg Egan’s novels, or are knowledgeable about universe theories, you can contribute by:

  • Designing the Protocol: Help refine the protocol design, particularly in areas such as object interactions and positioning, which are current focuses.
  • Documenting the Protocol: Expand and improve the documentation to make the protocol more accessible to others.

Build

Developers can contribute to several technical areas:

  • Core Contracts: Participate in implementing the protocol on universe chains, currently focusing on Ethereum using Solidity and Foundry.
  • Reference Chain: Contribute to the development of the Previous chain based on Substrate. The probe (bridge) is being developed using reth’s ExEx, both implemented in Rust.
  • Compilers: Help develop or improve compilers for kind contracts to WASM. A basic, functional compiler, kind-as, is available (AssemblyScript, TypeScript), with kind-rs (Rust) planned.
  • Tools: Enhance developer tools like pre-cli, a command-line interface for the protocol that interacts with the Previous chain and core contracts, written in TypeScript.

Create

Whether you’re an artist, musician, app developer, game developer, or any type of creative professional, consider how mutable, evolvable, and interoperable NFTs can unlock new possibilities for your work. We’d love to explore these opportunities with you.

Contacts

We’re always open to new ideas and collaborations! If you’d like to get in touch:

  • Follow Brice for updates.
  • Send Brice a DM for inquiries or opportunities.

We look forward to connecting with you!