Transaction Context

Every transaction has the execution context. The context is a set of predefined variables that are available to the program during execution. For example, every transaction has a sender address, and the transaction context contains a variable that holds the sender address.

The transaction context is available to the program through the TxContext struct. The struct is defined in the sui::tx_context module and contains the following fields:

// File: sui-framework/sources/tx_context.move
/// Information about the transaction currently being executed.
/// This cannot be constructed by a transaction--it is a privileged object created by
/// the VM and passed in to the entrypoint of the transaction as `&mut TxContext`.
struct TxContext has drop {
    /// The address of the user that signed the current transaction
    sender: address,
    /// Hash of the current transaction
    tx_hash: vector<u8>,
    /// The current epoch number
    epoch: u64,
    /// Timestamp that the epoch started at
    epoch_timestamp_ms: u64,
    /// Counter recording the number of fresh id's created while executing
    /// this transaction. Always 0 at the start of a transaction
    ids_created: u64
}

Transaction context cannot be constructed manually or directly modified. It is created by the system and passed to the function as a reference in a transaction. Any function called in a Transaction has access to the context and can pass it into the nested calls.

TxContext has to be the last argument in the function signature.

Reading the Transaction Context

With only exception of the ids_created, all of the fields in the TxContext have getters. The getters are defined in the sui::tx_context module and are available to the program. The getters don't require &mut because they don't modify the context.

public fun some_action(ctx: &TxContext) {
    let me = ctx.sender();
    let epoch = ctx.epoch();
    let digest = ctx.digest();
    // ...
}

Mutability

The TxContext is required to create new objects (or just UIDs) in the system. New UIDs are derived from the transaction digest, and for the digest to be unique, there needs to be a changing parameter. Sui uses the ids_created field for that. Every time a new UID is created, the ids_created field is incremented by one. This way, the digest is always unique.

Internally, it is represented as the derive_id function:

// File: sui-framework/sources/tx_context.move
native fun derive_id(tx_hash: vector<u8>, ids_created: u64): address;

Generating unique addresses

The underlying derive_id function can also be utilized in your program to generate unique addresses. The function itself is not exposed, but a wrapper function fresh_object_address is available in the sui::tx_context module. It may be useful if you need to generate a unique identifier in your program.

// File: sui-framework/sources/tx_context.move
/// Create an `address` that has not been used. As it is an object address, it will never
/// occur as the address for a user.
/// In other words, the generated address is a globally unique object ID.
public fun fresh_object_address(ctx: &mut TxContext): address {
    let ids_created = ctx.ids_created;
    let id = derive_id(*&ctx.tx_hash, ids_created);
    ctx.ids_created = ids_created + 1;
    id
}