Use this file to discover all available pages before exploring further.
Sui’s transaction model is unique in its support for Programmable Transaction Blocks (PTBs), which allow you to chain multiple operations together atomically. This enables complex operations to be executed efficiently in a single transaction.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, IntoStaticStr)]pub enum TransactionKind { /// A transaction that allows the interleaving of native commands and Move calls ProgrammableTransaction(ProgrammableTransaction), /// A system transaction that will update epoch information on-chain. ChangeEpoch(ChangeEpoch), Genesis(GenesisTransaction), ConsensusCommitPrologue(ConsensusCommitPrologue), AuthenticatorStateUpdate(AuthenticatorStateUpdate), EndOfEpochTransaction(Vec<EndOfEpochTransactionKind>), RandomnessStateUpdate(RandomnessStateUpdate), ConsensusCommitPrologueV2(ConsensusCommitPrologueV2), ConsensusCommitPrologueV3(ConsensusCommitPrologueV3), ConsensusCommitPrologueV4(ConsensusCommitPrologueV4), /// A system transaction that is expressed as a PTB ProgrammableSystemTransaction(ProgrammableTransaction),}
Programmable Transactions
User-initiated transactions that can chain multiple commands
System Transactions
Special transactions for epoch changes and system state updates
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]pub enum CallArg { // contains no structs or objects Pure(Vec<u8>), // an object Object(ObjectArg), // Reservation to withdraw balance from a funds accumulator FundsWithdrawal(FundsWithdrawalArg),}
Pure Arguments
Object Arguments
Funds Withdrawal
Pure values like numbers, strings, or addresses encoded as bytes:
const tx = new Transaction();tx.moveCall({ target: '0x2::coin::split', arguments: [ tx.object(coinId), tx.pure.u64(1000), // Pure argument ],});
References to on-chain objects:
pub enum ObjectArg { // A Move object from fastpath ImmOrOwnedObject(ObjectRef), // A Move object from consensus SharedObject { id: ObjectID, initial_shared_version: SequenceNumber, mutability: SharedObjectMutability, }, // A Move object that can be received in this transaction Receiving(ObjectRef),}
Withdraw from address balance accumulators:
pub struct FundsWithdrawalArg { /// The reservation of the funds accumulator to withdraw pub reservation: Reservation, /// The type argument of the funds accumulator to withdraw pub type_arg: WithdrawalTypeArg, /// The source of the funds to withdraw pub withdraw_from: WithdrawFrom,}pub enum WithdrawFrom { /// Withdraw from the sender of the transaction Sender, /// Withdraw from the sponsor of the transaction (gas owner) Sponsor,}
Entry functions are special Move functions that can be called directly from transactions:
/// Entry functions can accept a reference to the `TxContext`/// (mutable or immutable) as their last parameter.entry fun share(bar: u64, ctx: &mut TxContext) { transfer::share_object(Foo { id: object::new(ctx), bar, })}/// Parameters passed to entry functions called in a programmable/// transaction block must be inputs to the transaction block,/// and not results of previous transactions.entry fun update(foo: &mut Foo, ctx: &TxContext) { foo.bar = ctx.epoch();}/// Entry functions can return types that have `drop`.entry fun bar(foo: &Foo): u64 { foo.bar}
Can be called from other Move modules and chained in PTBs:
/// This function cannot be `entry` because it returns a value/// that does not have `drop`.public fun foo(ctx: &mut TxContext): Foo { Foo { id: object::new(ctx), bar: 0 }}
Can return any type
Results can be passed to subsequent commands
More flexible for composition
Can be called directly from transactions but with limitations:
entry fun create_and_transfer(value: u64, recipient: address, ctx: &mut TxContext) { let obj = Object { id: object::new(ctx), value }; transfer::public_transfer(obj, recipient);}
Here’s a practical example using a shared counter:
/// This example demonstrates a basic use of a shared object./// Rules:/// - anyone can create and share a counter/// - everyone can increment a counter by 1/// - the owner of the counter can reset it to any valuemodule basics::counter { /// A shared counter. public struct Counter has key { id: UID, owner: address, value: u64, } /// Create and share a Counter object. public fun create(ctx: &mut TxContext) { transfer::share_object(Counter { id: object::new(ctx), owner: ctx.sender(), value: 0, }) } /// Increment a counter by 1. public fun increment(counter: &mut Counter) { counter.value = counter.value + 1; } /// Set value (only runnable by the Counter owner) public fun set_value(counter: &mut Counter, value: u64, ctx: &TxContext) { assert!(counter.owner == ctx.sender()); counter.value = value; }}