Skip to main content

Module 0x2::versioned

use 0x2::dynamic_field;
use 0x2::object;
use 0x2::tx_context;

Resource Versioned

A wrapper type that supports versioning of the inner type. The inner type is a dynamic field of the Versioned object, and is keyed using version. User of this type could load the inner object using corresponding type based on the version. You can also upgrade the inner object to a new type version. If you want to support lazy upgrade of the inner type, one caveat is that all APIs would have to use mutable reference even if it's a read-only API.

struct Versioned has store, key
id: object::UID
version: u64

Struct VersionChangeCap

Represents a hot potato object generated when we take out the dynamic field. This is to make sure that we always put a new value back.

struct VersionChangeCap
versioned_id: object::ID
old_version: u64


Failed to upgrade the inner object due to invalid capability or new version.

const EInvalidUpgrade: u64 = 0;

Function create

Create a new Versioned object that contains a initial value of type T with an initial version.

public fun create<T: store>(init_version: u64, init_value: T, ctx: &mut tx_context::TxContext): versioned::Versioned
public fun create<T: store>(init_version: u64, init_value: T, ctx: &mut TxContext): Versioned {
    let mut self = Versioned {
        id: object::new(ctx),
        version: init_version,
    dynamic_field::add(&mut, init_version, init_value);

Function version

Get the current version of the inner type.

public fun version(self: &versioned::Versioned): u64
public fun version(self: &Versioned): u64 {

Function load_value

Load the inner value based on the current version. Caller specifies an expected type T. If the type mismatch, the load will fail.

public fun load_value<T: store>(self: &versioned::Versioned): &T
public fun load_value<T: store>(self: &Versioned): &T {
    dynamic_field::borrow(&, self.version)

Function load_value_mut

Similar to load_value, but return a mutable reference.

public fun load_value_mut<T: store>(self: &mut versioned::Versioned): &mut T
public fun load_value_mut<T: store>(self: &mut Versioned): &mut T {
    dynamic_field::borrow_mut(&mut, self.version)

Function remove_value_for_upgrade

Take the inner object out for upgrade. To ensure we always upgrade properly, a capability object is returned and must be used when we upgrade.

public fun remove_value_for_upgrade<T: store>(self: &mut versioned::Versioned): (T, versioned::VersionChangeCap)
public fun remove_value_for_upgrade<T: store>(self: &mut Versioned): (T, VersionChangeCap) {
        dynamic_field::remove(&mut, self.version),
        VersionChangeCap {
            versioned_id: object::id(self),
            old_version: self.version,

Function upgrade

Upgrade the inner object with a new version and new value. Must use the capability returned by calling remove_value_for_upgrade.

public fun upgrade<T: store>(self: &mut versioned::Versioned, new_version: u64, new_value: T, cap: versioned::VersionChangeCap)
public fun upgrade<T: store>(self: &mut Versioned, new_version: u64, new_value: T, cap: VersionChangeCap) {
    let VersionChangeCap { versioned_id, old_version } = cap;
    assert!(versioned_id == object::id(self), EInvalidUpgrade);
    assert!(old_version < new_version, EInvalidUpgrade);
    dynamic_field::add(&mut, new_version, new_value);
    self.version = new_version;

Function destroy

Destroy this Versioned container, and return the inner object.

public fun destroy<T: store>(self: versioned::Versioned): T
public fun destroy<T: store>(self: Versioned): T {
    let Versioned { mut id, version } = self;
    let ret = dynamic_field::remove(&mut id, version);