Skip to main content

Transferrable Witness

The transferrable witness pattern is based on a combination of capability and witness patterns. Because you should be careful with the witness pattern, you should allow only authorized users to spawn it (ideally only once). Some scenarios, however, require type authorization by module X to be used in another module Y. Or, possibly, there's a case where authorization should be performed after some time.

For these rather rare scenarios, a storable witness is a good solution.

module examples::transferable_witness {
use sui::transfer;
use sui::object::{Self, UID};
use sui::tx_context::{Self, TxContext};


/// Witness now has a `store` that allows us to store it inside a wrapper.
struct WITNESS has store, drop {}


/// Carries the witness type. Can be used only once to get a Witness.
struct WitnessCarrier has key { id: UID, witness: WITNESS }


/// Send a `WitnessCarrier` to the module publisher.
fun init(ctx: &mut TxContext) {
transfer::transfer(
WitnessCarrier { id: object::new(ctx), witness: WITNESS {} },
tx_context::sender(ctx)
)
}


/// Unwrap a carrier and get the inner WITNESS type.
public fun get_witness(carrier: WitnessCarrier): WITNESS {
let WitnessCarrier { id, witness } = carrier;
object::delete(id);
witness
}
}