---
# System prepended metadata

title: Dojo Enums and Uninitialized Storage

---

# Dojo Enums and Uninitialized Storage

We have identified an issue in Dojo storage when working with enums and uninitialized storage.

## Dojo Storage Overview
Before describing the issue, here's a brief summary of how Dojo storage works:

1. A model is defined as a Cairo struct.
2. This model is serialized using the `Serde` trait and written to world storage via `world.model_write(@m)`.
3. The world contract's storage acts as a database, where serialized data is written through syscalls to specific storage locations.

Since serialization is handled by the `Serde` trait, enums are serialized as follows:
1. The variant index is stored as the first `felt`.
2. If the variant contains a value (i.e., is not the unit type `()`), the serialized value occupies the remaining `felt`s.

For example, the `Option<T>` enum is serialized as:
```rust
enum Option<T> {
    Some: T,
    None,
}

let a = Option::None;
// Serialized = [0x1]

let b = Option::Some(2);
// Serialized = [0x0, 0x2]
```

In Starknet contracts, the Cairo compiler increments variant indices by `1`, ensuring that uninitialized storage defaults to a predictable variant.
Since Dojo uses `Serde`, this increment is not happening.

## Security Considerations
Given this behavior, consider the following model:
```rust
struct MyModel {
    #[key]
    id: u32,
    score: Option<u32>,
}
```
If this model is read from storage before being explicitly written, the world’s storage remains uninitialized (filled with `0x0`s). This results in:
```rust
let my_key: u32 = 0x1234;

// Reading an uninitialized model from storage.
let m = world.read_model(my_key);

// This assertion will revert Cairo execution.
// assert(m == None)

if m.score.is_some() {
    // Unexpected execution: `Some(0)` is returned instead of `None`.
} else {
    // Expected behavior, but will not occur in this case.
}
```
Here, `Some(0)` is returned instead of `None` because `Some` is the first variant of `Option<T>`, leading to unintended behavior when relying on `score` for logic for uninitialized models.

For custom enums, consider:
```rust
enum MyEnum {
    NotSet,
    Submitted: u32,
    Validated: felt252,
}
```
Reading uninitialized storage will return `MyEnum::NotSet`, as it is the first variant.

## Solutions at application level

1. Handling `Option<T>` at the Application Level
- Ensure models are explicitly initialized before being used.
- Avoid relying on `Option<T>` for initialization checks. Instead, use a separate `bool` or `integer` field, as these default to `0x0`.

2. Ordering Custom Enum Variants
- Define the default variant as the first variant to ensure correct behavior when reading uninitialized storage.

## Considerations for Dojo Core fix
We are investigating solutions that do not break existing storage in deployed worlds, though this presents challenges.

Possible Approaches:

1. **Introducing `DojoOption<T>`**
   - A custom `DojoOption<T>` type where `None` is explicitly stored as `0x0`.
   - Implementing `Into<Option<T>>` would allow seamless conversion.
   - This approach is non-breaking but requires model upgrades or conversions while fetching data.

2. **Incrementing Variant Indices**
   - Apply the Cairo compiler’s approach by shifting variant indices by `1`.
   - `0x0` would then explicitly map to the default variant.
   - This would break existing storage and lacks backward compatibility + some challenges for the impl.

3. **Modifying `Introspect` for `Option<T>`**
   - Adjust `Option<T>` handling internally to map `None` to `0x0` and `Some` to `0x1`.
   - Like the previous approach, this would break existing storage.

## Conclusion
If your project relies on `Option<T>` or custom enums, this issue may be critical. We recommend reviewing your usage and considering explicit initialization strategies when applicable.

For projects already on `mainnet`, upgrading the contract to modify logic or adding a dedicated initialization field can mitigate potential security risks.

This issue affects all versions since Dojo `1.0.0`.
