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:

  1. Calling the method associated with the transaction type
    1. Native transaction methods:
      1. sui_transferSui
      2. sui_transferObject
    2. Move call transaction methods:
      1. sui_moveCall
      2. sui_mergeCoins
      3. sui_splitCoin
    3. Move publish transaction method:
      1. sui_publish
  2. Signing the transaction
  3. 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:

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"
  }
}
  1. 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==

  1. Execute the transaction and wait for results if desired

Request types:

  1. WaitForEffectsCert: waits for TransactionEffectsCert and then return to client. This mode is a proxy for transaction finality.
  2. 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.