Sui Programmable Transaction Basics
This example starts by constructing a transaction to send SUI. To construct transactions, import the
Transaction
class and construct it:
You can then add transactions to the transaction .
You can attach multiple transactions of the same type to a transaction, as well. For example, to get a list of transfers and iterate over them to transfer coins to each of them:
After you have the transaction defined, you can directly execute it with a signer using
signAndExecuteTransaction
.
Observing the results of a transaction
When you use client.signAndExecuteTransaction
or client.executeTransactionBlock
, the transaction
will be finalized on the blockchain before the function resolves, but the effects of the transaction
may not be immediately observable.
There are 2 ways to observe the results of a transaction. Methods like
client.signAndExecuteTransaction
accept an options
object with options like showObjectChanges
and showBalanceChanges
(see
the SuiClient docs for more details). These options will cause
the request to contain additional details about the effects of the transaction that can be
immediately displayed to the user, or used for further processing in your application.
The other way effects of transactions can be observed is by querying other RPC methods like
client.getBalances
that return objects or balances owned by a specific address. These RPC calls
depend on the RPC node having indexed the effects of the transaction, which may not have happened
immediately after a transaction has been executed. To ensure that effects of a transaction are
represented in future RPC calls, you can use the waitForTransaction
method on the client:
Once waitForTransaction
resolves, any future RPC calls will be guaranteed to reflect the effects
of the transaction.
Transactions
Programmable Transactions have two key concepts: inputs and transactions.
Transactions are steps of execution in the transaction. Each Transaction in a Transaction takes a set of inputs, and produces results. The inputs for a transaction depend on the kind of transaction. Sui supports following transactions:
tx.splitCoins(coin, amounts)
- Creates new coins with the defined amounts, split from the provided coin. Returns the coins so that it can be used in subsequent transactions.- Example:
tx.splitCoins(tx.gas, [100, 200])
- Example:
tx.mergeCoins(destinationCoin, sourceCoins)
- Merges the sourceCoins into the destinationCoin.- Example:
tx.mergeCoins(tx.object(coin1), [tx.object(coin2), tx.object(coin3)])
- Example:
tx.transferObjects(objects, address)
- Transfers a list of objects to the specified address.- Example:
tx.transferObjects([tx.object(thing1), tx.object(thing2)], myAddress)
- Example:
tx.moveCall({ target, arguments, typeArguments })
- Executes a Move call. Returns whatever the Sui Move call returns.- Example:
tx.moveCall({ target: '0x2::devnet_nft::mint', arguments: [tx.pure.string(name), tx.pure.string(description), tx.pure.string(image)] })
- Example:
tx.makeMoveVec({ type, elements })
- Constructs a vector of objects that can be passed into amoveCall
. This is required as there’s no way to define a vector as an input.- Example:
tx.makeMoveVec({ elements: [tx.object(id1), tx.object(id2)] })
- Example:
tx.publish(modules, dependencies)
- Publishes a Move package. Returns the upgrade capability object.
Passing inputs to a transaction
Transaction inputs can be provided in a number of different ways, depending on the transaction, and the type of value being provided.
JavaScript values
For specific transaction arguments (amounts
in splitCoins
, and address
in transferObjects
)
the expected type is known ahead of time, and you can directly pass raw javascript values when
calling the transaction method. appropriate Move type automatically.
Pure values
When providing inputs that are not on chain objects, the values must be serialized as
BCS, which can be done using tx.pure
eg,
tx.pure.address(address)
or tx.pure(bcs.vector(bcs.U8).serialize(bytes))
.
tx.pure
can be called as a function that accepts a SerializedBcs object, or as a namespace that
contains functions for each of the supported types.
To pass vector
or option
types, you can pass use the corresponding methods on tx.pure
, use
tx.pure as a function with a type argument, or serialize the value before passing it to tx.pure
using the bcs sdk:
Object references
To use an on chain object as a transaction input, you must pass a reference to that object. This can
be done by calling tx.object
with the object id. Transaction arguments that only accept objects
(like objects
in transferObjects
) will automatically treat any provided strings as objects ids.
For methods like moveCall
that accept both objects and other types, you must explicitly call
tx.object
to convert the id to an object reference.
When building a transaction, Sui expects all objects to be fully resolved, including the object
version. The SDK automatically looks up the current version of objects for any provided object
reference when building a transaction. If the object reference is used as a receiving argument to a
moveCall
, the object reference is automatically converted to a receiving transaction argument.
This greatly simplifies building transactions, but requires additional RPC calls. You can optimize
this process by providing a fully resolved object reference instead:
Object helpers
There are a handful of specific object types that can be referenced through helper methods on tx.object:
Transaction results
You can also use the result of a transaction as an argument in a subsequent transactions. Each transaction method on the transaction builder returns a reference to the transaction result.
When a transaction returns multiple results, you can access the result at a specific index either using destructuring, or array indexes.
Get transaction bytes
If you need the transaction bytes, instead of signing or executing the transaction, you can use the
build
method on the transaction builder itself.
Important: You might need to explicitly call setSender()
on the transaction to ensure that the
sender
field is populated. This is normally done by the signer before signing the transaction, but
will not be done automatically if you’re building the transaction bytes yourself.
In most cases, building requires your SuiClient to fully resolve input values.
If you have transaction bytes, you can also convert them back into a Transaction
class: