通常のWitnessは型の所有権を静的に証明する優れた方法ですが、Witnessが一度だけインスタンス化されることを保証する必要がある場合があります。これがOne Time Witness(OTW)の目的です。

定義

OTWは一度だけ使用できる特別な種類のWitnessです。手動で作成することはできず、モジュールごとに一意であることが保証されています。Sui Adapterは、以下のルールに従う型をOTWとして扱います:

  1. drop能力のみを持つ。
  2. フィールドを持たない。
  3. ジェネリック型ではない。
  4. モジュール名に基づいて、すべて大文字で命名される。

以下はOTWの例です:

module book::one_time {
    /// `book::one_time`モジュールのOTW。
    /// `drop`のみ、フィールドなし、ジェネリックなし、すべて大文字。
    public struct ONE_TIME has drop {}

    /// `ONE_TIME`のインスタンスを最初の引数として受け取る。
    fun init(otw: ONE_TIME, ctx: &mut TxContext) {
        // OTWを使って何かを行う
    }
}

OTWは手動で構築することはできず、そのような試みはコンパイルエラーになります。OTWはモジュール初期化子(Module Initializer)の最初の引数として受け取ることができます。そして、init関数はモジュールごとに一度だけ呼び出されるため、OTWは一度だけインスタンス化されることが保証されます。

OTWの強制

型がOTWであるかどうかをチェックするために、Sui フレームワークのSui::typesモジュールは特別な関数is_one_time_witnessを提供しています。これを使用して型がOTWであるかどうかをチェックできます。

use sui::types;

const ENotOneTimeWitness: u64 = 1;

/// OTWを引数として受け取り、型がOTWでない場合は中断する。
public fun takes_witness<T: drop>(otw: T) {
    assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness);
}

まとめ

OTWパターンは、型が一度だけ使用されることを保証する優れた方法です。ほとんどの開発者はOTWの定義と受け取り方を理解する必要がありますが、OTWのチェックと強制は主にライブラリやフレームワークで必要とされます。例えば、sui::coinモジュールはcoin::create_currencyメソッドでOTWを要求し、それによってcoin::TreasuryCapが一度だけ作成されることを強制しています。

OTWは強力なツールであり、次のセクションで取り上げるPublisherオブジェクトの基礎を築きます。

The Move Book へ戻る