Sui Transactions Guide
Learn about building transactions on Sui using Shinami.
Background
Transactions on Sui require that dependencies be explicit. This enables massively parallel execution, where only a subset of transactions that have an effect on some shared state (i.e. bidding on an auction) need to go through consensus to be ordered and executed sequentially. For common transactions (i.e. transfers between users), Sui validates the transactions individually, rather than batching them in traditional blocks. Each successful transaction quickly obtains a certificate of finality that proves to anyone that the transaction will be processed by the Sui network.
Building Transactions
Sui's "multi-lane" approach to transaction validation has a major advantage in reducing latency, but the process of submitting a transaction is also a bit more involved. Native transactions (transfers), Move call transactions (invoking smart contracts) or Move publish transactions (publishing smart contracts) each involve a three step process:
- Calling the method associated with the transaction type
- Native transaction methods:
- sui_transferSui
- sui_transferObject
- Move call transaction methods:
- sui_moveCall
- sui_mergeCoins
- sui_splitCoin
- Move publish transaction method:
- sui_publish
- Native transaction methods:
- Signing the transaction
- Executing the transaction using the
sui_executeTransaction
method
Different transaction methods have different parameters, but all transaction types and methods on Sui follow this same three step process.
Detailed Example
Prerequisites:
You will need to install Sui binaries to use the Sui CLI for signing transactions.
You’ll also need Sui tokens to execute transactions:
- Join Sui's Discord
- Request Sui test tokens on #devnet-faucet
- Check your transaction hash on the Sui Explorer
sui_transferObject
1. Create a transaction to transfer an object from one address to another
curl https://node.shinami.com/api/v1/<<apiKey>> \
-X POST \
-H 'Content-Type: application/json' \
-d '{ "jsonrpc":"2.0",
"method":"sui_transferObject",
"params":["{{signer_address}}",
"{{object_id}}",
"{{gas_object_id}}",
{{gas_budget}},
"{{recipient_address}}"],
"id":1}' | json_pp
Native transfer by sui_transferObject
is supported for any object that allows for public transfers. Some objects cannot be transferred natively and require a Move call transaction instead.
You should replace {{signer_address}}
and {{recipient_address}}
in the command above with address values. You should also replace {{object_id}}
and {{gas_object_id}}
in the command above with actual object IDs, for example one obtained from sui_getObjectsOwnedbyAddress
. You can see that all gas objects generated during genesis are of Coin/SUI
type.
For this call to work, objects represented by both {{object_id}}
and {{gas_object_id}}
must be owned by the address represented by {{signer_address}}
. You can either include an object ID for {{gas_object_id}}
or the gateway will pick an object from the signer's possession if not provided.
The transaction data response should resemble the following:
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"tx_bytes" : "VHJhbnNhY3Rpb25EYXRhOjoAAFHe8jecgzoGWyGlZ1sJ2KBFN8aZF7NIkDsM+3X8mrVCa7adg9HnVqUBAAAAAAAAACDOlrjlT0A18D0DqJLTU28ChUfRFtgHprmuOGCHYdv8YVHe8jecgzoGWyGlZ1sJ2KBFN8aZdZnY6h3kyWFtB38Wyg6zjN7KzAcBAAAAAAAAACDxI+LSHrFUxU0G8bPMXhF+46hpchJ22IHlpPv4FgNvGOgDAAAAAAAA"
}
}
- Sign the transaction using the Sui keytool
sui keytool sign --address <owner_address> --data <tx_bytes>
You'll need the Sui CLI to use the Sui keytool. The keytool will create and print out the signature and public key information. You will see output resembling:
2022-04-25T18:50:06.031722Z INFO sui::sui_commands: Data to sign : VHJhbnNhY3Rpb25EYXRhOjoAAFHe8jecgzoGWyGlZ1sJ2KBFN8aZF7NIkDsM+3X8mrVCa7adg9HnVqUBAAAAAAAAACDOlrjlT0A18D0DqJLTU28ChUfRFtgHprmuOGCHYdv8YVHe8jecgzoGWyGlZ1sJ2KBFN8aZdZnY6h3kyWFtB38Wyg6zjN7KzAcBAAAAAAAAACDxI+LSHrFUxU0G8bPMXhF+46hpchJ22IHlpPv4FgNvGOgDAAAAAAAA
2022-04-25T18:50:06.031765Z INFO sui::sui_commands: Address : 0x51def2379c833a065b21a5675b09d8a04537c699
2022-04-25T18:50:06.031911Z INFO sui::sui_commands: Public Key Base64: H82FDLUZN1u0+6UdZilxu9HDT5rPd3khKo2UJoCPJFo=
2022-04-25T18:50:06.031925Z INFO sui::sui_commands: Signature : 6vc+ku0RsMKdky8DRfoy/hw6eCQ3YsadH6rZ9WUCwGTAumuWER3TOJRw7u7F4QaHkqUsIPfJN9GRraSX+N8ADQ==
- Execute the transaction and wait for results if desired
Request types:
- WaitForEffectsCert: waits for TransactionEffectsCert and then return to client. This mode is a proxy for transaction finality.
- WaitForLocalExecution: waits for TransactionEffectsCert and makes sure the node executed the transaction locally before returning the client. The local execution makes sure this node is aware of this transaction when the client fires subsequent queries. However, if the node fails to execute the transaction locally in a timely manner, a bool type in the response is set to false.
curl https://node.shinami.com/api/v1/<<apiKey>> \
-X POST \
-H 'Content-Type: application/json' \
-d '{ "jsonrpc":"2.0",
"method":"sui_executeTransaction",
"params":[{"{{tx_bytes}}",
"{{sig_scheme}}",
"{{signature}}",
"{{pub_key}}",
"{{request_type}}"}],
"id":1}' | json_pp
The response should resemble the following:
{
"id" : 1,
"jsonrpc" : "2.0",
"result" : {
"EffectResponse": {
"certificate": {
"authSignInfo": {
"epoch": 0,
"signature": [],
"signers_map": [
58,
48,
0,
0,
0,
0,
0,
0
]
},
"data": {
"gasBudget": 1000,
"gasPayment": {
"digest": "9jzkk/US8LLPt8QqB86RMMttBZo4jYhhU2y5xbgamo0=",
"objectId": "0xc6a93d051651fe2e4eefae28134925683890a942",
"version": 2
},
"sender": "0xd067c3342641a4ceaab2c1dbdad0112b2e3e48f8",
"transactions": [
{
"TransferObject": {
"objectRef": {
"digest": "O8fcl1q3X8hleTU29m5kGJBQNg9iPciKu4MAGAzdCo8=",
"objectId": "0xc46c2d64a7a5b1d93b2d8646805d8d2a122fccdb",
"version": 2
},
"recipient": "0x1758edb9260d2a86c836efc05f17e5c59525e404"
}
}
]
},
"transactionDigest": "M9fSFZs98pa0bdZL7Fdgmj8vtK2LRuL9TJ8l1EMo3VA=",
"txSignature": "AE6A2cVJlnz4OqAZUvmcIWHzpVs8GJMpmkNeUwDS4zZpFlYlncSRfZQLI+y35S7JUWBjeJjQlOKP7VKMCcu2/gOqZZ9KpAIX18Y+wOxONUUOvAZgRy6HbU5Y1LOiSJLvkQ=="
},
"effects": {
"gasObject": {
"owner": {
"ObjectOwner": "0xd067c3342641a4ceaab2c1dbdad0112b2e3e48f8"
},
"reference": {
"digest": "9jzkk/US8LLPt8QqB86RMMttBZo4jYhhU2y5xbgamo0=",
"objectId": "0xc6a93d051651fe2e4eefae28134925683890a942",
"version": 2
}
},
"gasUsed": {
"computationCost": 100,
"storageCost": 100,
"storageRebate": 10
},
"mutated": [
{
"owner": {
"AddressOwner": "0xd067c3342641a4ceaab2c1dbdad0112b2e3e48f8"
},
"reference": {
"digest": "9jzkk/US8LLPt8QqB86RMMttBZo4jYhhU2y5xbgamo0=",
"objectId": "0xc6a93d051651fe2e4eefae28134925683890a942",
"version": 2
}
},
{
"owner": {
"AddressOwner": "0x1758edb9260d2a86c836efc05f17e5c59525e404"
},
"reference": {
"digest": "O8fcl1q3X8hleTU29m5kGJBQNg9iPciKu4MAGAzdCo8=",
"objectId": "0xc46c2d64a7a5b1d93b2d8646805d8d2a122fccdb",
"version": 2
}
}
],
"status": {
"status": "success"
},
"transactionDigest": "zlFNt7v1DvUYwZWnBTdj0Kjf2ra5Ru6fOVRUkxmsfcY="
},
"timestamp_ms": null
}
}
}
You can find a full list of methods and descriptions in the Sui API Reference section.
Updated 8 months ago