From c7be001e64ef953db4e2512db91113102bd44670 Mon Sep 17 00:00:00 2001 From: ronny-mysten <118224482+ronny-mysten@users.noreply.github.com> Date: Mon, 5 Dec 2022 19:31:33 -0700 Subject: [PATCH 1/2] Added --ver-dep flag to sui cli --- doc/src/build/cli-client.md | 62 +++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/doc/src/build/cli-client.md b/doc/src/build/cli-client.md index a7a2d18d1eca..5ae1092af124 100644 --- a/doc/src/build/cli-client.md +++ b/doc/src/build/cli-client.md @@ -507,25 +507,24 @@ id: 0x471c8e241d0473c34753461529b70f9c4ed3151b[1] ## Publish packages -In order for user-written code to be available in Sui, it must be -*published* to Sui's [distributed ledger](../learn/how-sui-works.md#architecture). -Please see the [Move developer documentation](move/index.md) for a -description on how to [write a simple Move code package](move/write-package.md), -which we can publish using Sui client's `publish` command. +You must publish packages to the Sui [distributed ledger](../learn/how-sui-works.md#architecture) for the code you developed to be available in Sui. To publish packages with the Sui client, use the `publish` command. + +The publish command requires that you specify the directory where your package lives using the `--path` parameter. The value is the path to the `my_move_package` as per the [package creation description](move/write-package.md). You must also provide a `gas` object to pay for publishing the package and a `gas-budget` value. -> **Important:** All calls to functions in the `debug` module must be removed from no-test code -> before the new module can be published (test code is marked with the `#[test]` annotation). +Parameters used for the `publish` command example: +* `--path` - Defines the path to the Move package to publish. +* `--gas` - The Coin object used to pay for gas. +* `--gas-budget` - Gas budget for running module initializers. +* `--verify-dependencies` - Optional flag to have the CLI check that a dependency exists on-chain. -The publish command -requires us to specify a directory where the user-defined package lives. -It's the path to the `my_move_package` as per the -[package creation description](move/write-package.md), a gas -object that will be used to pay for publishing the package (we use the -same gas object we used to pay for the function call in the -[Calling Move code](#calling-move-code)) section, and gas budget to put -an upper limit we use 1000 as our gas budget. +Refer to the [Move developer documentation](move/index.md) for a +description on how to [write a simple Move code package](move/write-package.md), +which you can then publish using the Sui client `publish` command. -Let us use the same address for publishing that we used for calling Move code in the previous [section](#calling-move-code) (`0x3cbf06e9997b3864e3baad6bc0f0ef8ec423cd75`) which now has 4 objects left: +> **Important:** You must remove all calls to functions in the `debug` module from no-test code +> before you can publish the new module (test code is marked with the `#[test]` annotation). + +Use the same address for publishing that we used for calling Move code in the previous [section](#calling-move-code) (`0x3cbf06e9997b3864e3baad6bc0f0ef8ec423cd75`) which now has four objects left: ```shell $ sui client objects 0x3cbf06e9997b3864e3baad6bc0f0ef8ec423cd75 @@ -549,10 +548,22 @@ that the location of the package's sources is in the `PATH_TO_PACKAGE` environment variable): ```shell -$ sui client publish --path $PATH_TO_PACKAGE/my_move_package --gas-budget 30000 +$ sui client publish --path $PATH_TO_PACKAGE/my_move_package --gas 0xc8add7b4073900ffb0a8b4fe7d70a7db454c2e19 --gas-budget 30000 --verify-dependencies ``` -The result of running this command should look as follows: +The call uses the optional `--verify-dependencies` flag to verify the bytecode for dependencies found at their respective published addresses matches the bytecode you get when compiling that dependency from source code. If the bytecode for a dependency does not match, your package does not publish and you receive an error message indicating which package and module the mismatch was found: + +```shell +Local dependency did not match its on-chain version at
:::: +``` + +The `--verify-dependencies` flag can fail the publish for other reasons, as well. +* There are modules missing, either in the local version of the dependency or on-chain. +* There's nothing at the address that the dependency points to (it was deleted or never existed). +* The address supplied for the dependency points to an object instead of a package. +* The CLI fails to connect to the node to fetch the package. + +If successful, your response resembles the following: ```shell ----- Certificate ---- @@ -577,19 +588,18 @@ swords_created: 0 Updated Gas : Coin { id: 0xc8add7b4073900ffb0a8b4fe7d70a7db454c2e19, value: 96929 } ``` -Please note that running this command resulted in creating an object representing the published package. -From now on, we can use the package object ID (`0xdbcee02bd4eb326122ced0a8540f15a057d82850`) in the Sui client's call -command just like we used `0x2` for built-in packages in the -[Calling Move code](#calling-move-code) section. +Running this command created an object representing the published package. +From now on, use the package object ID (`0xdbcee02bd4eb326122ced0a8540f15a057d82850`) in the Sui client call +command (similar to `0x2` used for built-in packages in the +[Calling Move code](#calling-move-code) section). Another object created as a result of package publishing is a -user-defined object (of type `Forge`) crated inside initializer +user-defined object (of type `Forge`) created inside the initializer function of the (only) module included in the published package - see the part of Move developer documentation concerning [module -initializers](move/debug-publish.md#module-initializers) for more details on module -initializers. +initializers](move/debug-publish.md#module-initializers) for more details. -Finally, we see that the gas object that was used to pay for +You might notice that the gas object that was used to pay for publishing was updated as well. > **Important:** If the publishing attempt results in an error regarding verification failure, From 318e2dc2927d453e290781c05db80c8013faf5d1 Mon Sep 17 00:00:00 2001 From: ronny-mysten <118224482+ronny-mysten@users.noreply.github.com> Date: Tue, 13 Dec 2022 08:36:52 -0700 Subject: [PATCH 2/2] Added json rpc examples --- .../walkthrough/check-object-details.md | 48 +++ .../walkthrough/check-owned-objects.md | 90 ++++++ doc/src/explore/walkthrough/index.md | 43 +++ doc/src/explore/walkthrough/merge-coins.md | 211 ++++++++++++ doc/src/explore/walkthrough/mint-swords.md | 246 ++++++++++++++ .../explore/walkthrough/publish-package.md | 91 ++++++ doc/src/explore/walkthrough/split-coin.md | 299 ++++++++++++++++++ .../explore/walkthrough/transfer-objects.md | 59 ++++ .../walkthrough/working-with-move-packages.md | 42 +++ 9 files changed, 1129 insertions(+) create mode 100644 doc/src/explore/walkthrough/check-object-details.md create mode 100644 doc/src/explore/walkthrough/check-owned-objects.md create mode 100644 doc/src/explore/walkthrough/index.md create mode 100644 doc/src/explore/walkthrough/merge-coins.md create mode 100644 doc/src/explore/walkthrough/mint-swords.md create mode 100644 doc/src/explore/walkthrough/publish-package.md create mode 100644 doc/src/explore/walkthrough/split-coin.md create mode 100644 doc/src/explore/walkthrough/transfer-objects.md create mode 100644 doc/src/explore/walkthrough/working-with-move-packages.md diff --git a/doc/src/explore/walkthrough/check-object-details.md b/doc/src/explore/walkthrough/check-object-details.md new file mode 100644 index 000000000000..c2864a13b5a8 --- /dev/null +++ b/doc/src/explore/walkthrough/check-object-details.md @@ -0,0 +1,48 @@ +--- +title: Check the details of an Object +--- + +In the previous example, you retrieved the objects your address owns. In this example, you use the `sui_getObject` method to check the `objectId` for one of those coins and its details. Enter the following commands in your terminal, replacing the given ID with one of the coin object IDs at your address. + +```sh +# Set the id as a variable +id="0x91be7b2c011125f748c308872d00c8f200cabe15" +# Create the JSON +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_getObject\", \"params\": [\"$id\"]}" +# Fire the request and save the result in a tmp file +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +After entering the last command, open the result.json file it created in an editor like Visual Studio Code. Use the editor to format the JSON, if necessary. If successful, your JSON resembles the following: + +```JSON +{ + "jsonrpc":"2.0", + "result":{ + "status":"Exists", + "details":{ + "data":{ + "dataType":"moveObject", + "type":"0x2::coin::Coin<0x2::sui::SUI>", + "has_public_transfer":true, + "fields":{ + "balance":10000000, + "id":{"id":"0x91be7b2c011125f748c308872d00c8f200cabe15"} + } + }, + "owner":{"AddressOwner":"0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12"}, + "previousTransaction":"8Dpc1+03kCviQRrB4hMUDT1z3bF+ZhlHtkG3RXHKuBg=", + "storageRebate":15, + "reference":{"objectId":"0x91be7b2c011125f748c308872d00c8f200cabe15", + "version":1, + "digest":"Bu5RPYiVWDDX4IshFqB8vsUdzBptTkhNK/Hm/b06wEA="}} + }, + "id":1 +} +``` + +The same parameters exist for this call as were available with [`sui_getObjectsOwnedByAddress`](/sui-jsonrpc#sui_getObjectsOwnedByAddress) (`digest`, `previousTransaction`, `owner`, `version`, and so on) but are in a slightly different shape with additional data. The `result` object, for example, contains a `details.data.fields.balance` parameter showing a value of `10000000`. This means that this SUI Coin object's value is 10,000,000 SUI. The faucet provided you with five such objects. If you check each one, you discover that their balance is the same. + +As mentioned, when you want to acquire another object that is priced in SUI, you need to send a Coin object with the exact balance as its price. You also must provide a Coin object to pay gas for the transaction. + +The splitting of Coins to facilitate transactions typically does not require user input or knowledge, so the process occurs quietly. In the next example, you split the coins manually to understand the process. \ No newline at end of file diff --git a/doc/src/explore/walkthrough/check-owned-objects.md b/doc/src/explore/walkthrough/check-owned-objects.md new file mode 100644 index 000000000000..8d4bf196f35e --- /dev/null +++ b/doc/src/explore/walkthrough/check-owned-objects.md @@ -0,0 +1,90 @@ +--- +title: Check the objects our address owns +--- + +*In Sui everything is an object.* Sui is object-centric and every object owns a UID. You might not be aware yet, but if you followed the previous steps then your address owns 5 objects that contain a specific amount of SUI tokens tapped from the Discord faucet. When considering SUI tokens, you can think of each Coin object as SUI banknotes. As such, your address actually has 5 banknotes, each with its own, currently equal denomination. + +If you want to transfer a SUI amount that is less than the denominated value of your SUI banknote, then you have to make change. To do this, you must split your large banknote into smaller denominations. For example, if you want to send 20,000 SUI to someone but all your banknotes contain 10,000,000 SUI, then you must split one of those banknotes into two smaller SUI banknotes, one with 20,000 SUI and another containing 9,980,000 SUI. You can then complete the transfer with your newly minted 20,000 SUI. In the end, you created two new SUI banknotes and deleted the original one. The actual process of splitting SUI objects typically completes without any direct involvement on your part, but is useful to understand. + +As mentioned, your address should now have SUI assigned. To check, you can make an RPC call using the [`sui_getObjectsOwnedByAddress`](/sui-jsonrpc#sui_getObjectsOwnedByAddress). For ease of use on a command line, save the JSON payload to a variable before making the actual call. + +```sh +data="{\"jsonrpc\": \"2.0\", \"method\": \"sui_getObjectsOwnedByAddress\", \"id\": 1, \"params\": [\"$address\"]}" +``` +Make the call using cURL: + +```sh +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc +``` + +If successful, the JSON response has the following shape: + +```JSON +{ + "jsonrpc": "2.0", + "result": [ + { + "objectId": "0x91be7b2c011125f748c308872d00c8f200cabe15", + "version": 1, + "digest": "Zusbw800Wk4+vpkei8JQD+EJiQEf8PvmdIQokHwX0N0=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "previousTransaction": "B2015vW4kYmFXLsBw/njGWUOQHdmszg8jsdygrUFTPw=" + }, + { + "objectId": "0x9f0afe6a6c3d72d281003b6f87ea84703113744c", + "version": 1, + "digest": "m0M5XSe4MLQWsz1mAPFAH8iztx8VHnZPNqYtCb4fc1k=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "previousTransaction": "3DEKooZaVHWiMrdjMb8e1h2kx2J+M9Yu5uJy2CHmgJ4=" + }, + { + "objectId": "0xb2a2f77bbddb5c9c84a2abbfdd282d609274f96b", + "version": 1, + "digest": "w3U7ZJsnpcLB+NPiFTGrOz58I/a9TRz0YPGFRPdjm6o=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "previousTransaction": "E5CGmStqkRq7fB6MPwLx5MBbR8MNtzFEiNVRnfNL3s8=" + }, + { + "objectId": "0xbb2d9b82ecc54012640d3cef122de4f394f8aa15", + "version": 1, + "digest": "dvRriMle+XIC9WHN0nEj+KD5rPWhLYBeXeFLAeCDSu8=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "previousTransaction": "bKioOVWJBniAlT1SlVUsspIiDDZABS+nvROSu3/RZmA=" + }, + { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 1, + "digest": "BptpMcUxbtjN0D9CGvtqSwS9odmEfW9pho+aIF/MiA4=", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "previousTransaction": "lBnZ6OXExGfd0C5EzCLlR2gXAT/aTn0EnOvwF5KJEOU=" + } + ], + "id": 1 +} +``` + +> **NOTE:** The response you receive in the terminal is not prettified like this example output, so it's a little difficult to parse. From this point forward, the example commands save the output to a JSON file so that you can more readily format the response if you're following along. + +The details of the response offers some observations into objects on the Sui network. For instance, +* `objectId` - Each object in the result has a UID assigned to its `objectId` parameter. This ID is unique for each object in the Sui network. +* `type` - Each object also has a `type` parameter set to `0x2::coin::Coin<0x2::sui::SUI`, where the `0x2` address can contain a number of packages that are native to Sui, like the SUI Coin module, the transfer function, the `TxContext` global object, and so on. In the case of this example, each object has a `type` of `0x2::sui::SUI`, which are SUI tokens. +* `owner` - The `owner` object provides the address of the object's current owner. +* `previousTransaction` - Every object has a `previousTransaction` value to verify its placement on-chain. +* `version` - The `version` value reports the number of transactions an object has been through. Because all the coins in this example are freshly minted by faucet, they have experienced a single transaction so far: `"version": 1`. + +Your address now has Coins assigned to it and you have retrieved a list of those objects. In the next example, you take a closer look at one of those Coins. \ No newline at end of file diff --git a/doc/src/explore/walkthrough/index.md b/doc/src/explore/walkthrough/index.md new file mode 100644 index 000000000000..6d43744f27cd --- /dev/null +++ b/doc/src/explore/walkthrough/index.md @@ -0,0 +1,43 @@ +--- +title: JSON RPC Examples +--- + +Welcome to this walkthrough of the Sui JSON Remote Procedure Call (RPC) protocol. Using the following series of examples, you interact with the Sui network to create and manipulate objects on the blockchain using the Sui Client CLI. + +## Prerequisites + +What you need: +* Sui Client CLI (installed when you install Sui). To check if you have Sui installed, type `which sui` in a command-line shell (terminal) window. If the terminal does not echo a path, you need to [install Sui](/devnet/build/install). +* An active address, preferably without any objects. You create an address when you first connect to Devnet with the `sui client` command. If you need a new address, use the `sui client new-address ed25519` command to create one with an `ed25519` key scheme. +* cURL is used in the examples. You can modify these calls to the language of your choice. If you need help installing, refer to the [Install Sui to Build](/build/install) topic. +* The examples use Git to download code from the internet. If you need help installing, refer to the [Install Sui to Build](/build/install) topic. + +## Setup + +**Note:** When reading about Sui, you often see Sui capitalized as both "Sui" and "SUI". Sui refers to the network, and SUI, all capital letters, refers to the token. + +Open a terminal window. If you are following along using cURL, use the same terminal window for all the commands in these examples. + +To begin, make sure your address exists and store its value to a variable to limit the amount of typing required in subsequent commands: + +```sh + sui client active-address + # 0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12 + address="0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" +``` + +**Note:** Sample values are provided throughout these examples to demonstrate what they should look like. Make sure to change them to the specific values for your environment. + +If the sui command does not return an address, [connect to Sui Devnet](https://docs.sui.io/build/devnet) to get one. + +To complete the following calls, you need to add SUI to your address. If using Devnet, join our [discord channel](https://discord.gg/sui) if you haven't already. After you are verified, type `!faucet
` in the the [devnet-faucet](https://discord.com/channels/916379725201563759/971488439931392130) channel, where `
` is the value you retrieve from the `sui client active-address` command. + +If using a local installation, then add SUI to your address. + +To complete setup, bind the devnet rpc server URL to a variable: + +```sh +rpc="https://fullnode.devnet.sui.io:443" +``` + +Now, you are ready to make your first call and see the SUI you own. diff --git a/doc/src/explore/walkthrough/merge-coins.md b/doc/src/explore/walkthrough/merge-coins.md new file mode 100644 index 000000000000..95236eb20e79 --- /dev/null +++ b/doc/src/explore/walkthrough/merge-coins.md @@ -0,0 +1,211 @@ +--- +title: Merge Two Coins +--- + +In this example, you merge two coins to check the rebate you get. The previous example demonstrated the cost of gas paid with the total amount itemized in the `effects` object. That object includes a `storage_rebate` value, which is the amount you get back when you delete the object. For Coin objects, the reasonable way to delete them is to merge them with other coins. To carry forward the banknote example used previously, this is the equivalent of gathering smaller banknotes and exchanging them for larger denominations. + +To merge, use the initial Coin whose address is already bound to `id` in your terminal. You need a coin to merge with, which in this example is the untouched Coin that is second in the list. + +As you might expect, the end result of the following call is that the second object no longer exists and the first Coin object has a larger balance (sum of the two Coins) with the same ID. + +```sh +# Bind the id of the second coin +id2="0x9f0afe6a6c3d72d281003b6f87ea84703113744c" +``` + +The method is `sui_mergeCoin` and the procedure is the same, but this time the `request_type` for the transaction is `ImmediateReturn`. The example continues by using the transaction digest and the `sui_getTransaction` to further see what happened to the execution. This example and those following might omit outputs already shown to focus attention on new responses. + +```sh +# Prepare data for the sui_mergeCoins method +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_mergeCoins\", \"params\": [\"$address\", \"$id\", \"$id2\", \"$gas_id\", 1000]}" + +# Fire the request +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json + +# Get the tx_bytes from the result +tx_bytes="VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAg61Q+9Nb1tpyLqvfx3DAp0d2s+c64rNfj1WaiqXiqd08DcGF5BGpvaW4BBwAAAAAAAAAAAAAAAAAAAAAAAAACA3N1aQNTVUkAAgEAkb57LAERJfdIwwiHLQDI8gDKvhUCAAAAAAAAACB9V3mu9pHYBp9Yq2Ms7Wd6ZLpCqzXGesc+TRFK1s8rnQEAnwr+amw9ctKBADtvh+qEcDETdEwBAAAAAAAAACCbQzldJ7gwtBazPWYA8UAfyLO3HxUedk82pi0Jvh9zWfwIv478w9s2IYqaMV/2x6C/DT0S6chaf0nA0GUmhWkNvVUv4XqDvS4CAAAAAAAAACDDQ9w3L/SkoSJ6hZD/iUXHxdqiYyei1KW1Fkwwx3gq0gEAAAAAAAAA6AMAAAAAAAA=" + +# Get the execute data +sui keytool sign --address "$address" --data "$tx_bytes" +# INFO sui::keytool: Address : 0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12 +# INFO sui::keytool: Flag Base64: AA== +# INFO sui::keytool: Public Key Base64: R904IKMQHbULGI+8g3aKNndZHcXbO3FSRoZF3QspcnY= +# INFO sui::keytool: Signature : HIP5rNVmmvlCVq6nwvd2Ls7Uu9zUGyvw8T6+1N0LAmph123cX+bG2fsqyYcVpyT0imQZooSxNsac+89HsZVcCA== + +# The public key and the scheme are the same +signature="HIP5rNVmmvlCVq6nwvd2Ls7Uu9zUGyvw8T6+1N0LAmph123cX+bG2fsqyYcVpyT0imQZooSxNsac+89HsZVcCA==" + +# Prepare to execute the transaction +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_executeTransaction\", \"params\": [\"$tx_bytes\", \"$scheme\",\"$signature\",\"$pub_key\",\"ImmediateReturn\"]}" + +# Request execution +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, the response resembles: + +```JSON +{ + "jsonrpc": "2.0", + "result": { + "ImmediateReturn": { + "tx_digest": "IuqUhuwnSp1LbJvWG8X9zbdl5LdiViJucAQb+KgYh2A=" + } + }, + "id": 1 +} +``` + +The `tx_digest` value is needed for the next call. Assign it to a variable: + +```sh +tx_digest="IuqUhuwnSp1LbJvWG8X9zbdl5LdiViJucAQb+KgYh2A=" + +# Prepare the data for the sui_getTransaction +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_getTransaction\", \"params\": [\"$tx_digest\"]}" + +# Send the request +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +A successful call here returns data similar to the following: + +```JSON +{ + "jsonrpc": "2.0", + "result": { + "certificate": { + "transactionDigest": "IuqUhuwnSp1LbJvWG8X9zbdl5LdiViJucAQb+KgYh2A=", + "data": { + "transactions": [ + { + "Call": { + "package": { + "objectId": "0x0000000000000000000000000000000000000002", + "version": 1, + "digest": "61Q+9Nb1tpyLqvfx3DAp0d2s+c64rNfj1WaiqXiqd08=" + }, + "module": "pay", + "function": "join", + "typeArguments": [ + "0x2::sui::SUI" + ], + "arguments": [ + "0x91be7b2c011125f748c308872d00c8f200cabe15", + "0x9f0afe6a6c3d72d281003b6f87ea84703113744c" + ] + } + } + ], + "sender": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12", + "gasPayment": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 2, + "digest": "w0PcNy/0pKEieoWQ/4lFx8XaomMnotSltRZMMMd4KtI=" + }, + "gasBudget": 1000 + }, + "txSignature": "AByD+azVZpr5Qlaup8L3di7O1Lvc1Bsr8PE+vtTdCwJqYddt3F/mxtn7KsmHFack9IpkGaKEsTbGnPvPR7GVXAhH3TggoxAdtQsYj7yDdoo2d1kdxds7cVJGhkXdCylydg==", + "authSignInfo": { + "epoch": 0, + "signature": "gkRkfIQWMESYbWtpiGLU45EbBvHTq8xufmp8TJkaYGYFunYWlGf1/6DMMisKrufm", + "signers_map": [ + 58, + 48, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 16, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 3, + 0 + ] + } + }, + "effects": { + "status": { + "status": "success" + }, + "gasUsed": { + "computationCost": 528, + "storageCost": 30, + "storageRebate": 45 + }, + "transactionDigest": "IuqUhuwnSp1LbJvWG8X9zbdl5LdiViJucAQb+KgYh2A=", + "mutated": [ + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0x91be7b2c011125f748c308872d00c8f200cabe15", + "version": 3, + "digest": "y3YuwQfasEHD5lamA4su5+melRJWpP3s37uNX/u7F38=" + } + }, + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 3, + "digest": "zMc4fVHWOg4vVMa8l1JM4erSJKxz7I8BlluS5dWKoZE=" + } + } + ], + "deleted": [ + { + "objectId": "0x9f0afe6a6c3d72d281003b6f87ea84703113744c", + "version": 2, + "digest": "Y2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2M=" + } + ], + "gasObject": { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 3, + "digest": "zMc4fVHWOg4vVMa8l1JM4erSJKxz7I8BlluS5dWKoZE=" + } + }, + "events": [ + { + "deleteObject": { + "packageId": "0x0000000000000000000000000000000000000002", + "transactionModule": "pay", + "sender": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12", + "objectId": "0x9f0afe6a6c3d72d281003b6f87ea84703113744c" + } + } + ], + "dependencies": [ + "PEGLG0dsS+4qPX6Qu77l2HauyB3eKsTfZoLExPp0GfU=", + "3DEKooZaVHWiMrdjMb8e1h2kx2J+M9Yu5uJy2CHmgJ4=" + ] + }, + "timestamp_ms": null, + "parsed_data": null + }, + "id": 1 +} +``` + +As the response shows, the Coin object used for gas and the first Coin object are mutated, and the other Coin no longer exists. The result is `45` SUI as rebate and the Coin object assigned to `id` now has a balance of `19990001` SUI (you can check this with `sui client gas`). + +With some straightforward examples completed from the previous exercises, you should be able to apply what you learned to similar calls like `sui_splitCoinEqual` and `sui_getRawObject` on your own. The exercises that follow interact with objects related to Move packages. diff --git a/doc/src/explore/walkthrough/mint-swords.md b/doc/src/explore/walkthrough/mint-swords.md new file mode 100644 index 000000000000..3b746ba6845d --- /dev/null +++ b/doc/src/explore/walkthrough/mint-swords.md @@ -0,0 +1,246 @@ +--- +title: Mint Swords +--- + +Start by checking your module on the ledger with the `sui_getNormalizedMoveModule` method. This is a GET method, which is gas-less. You need the module ID, which is provided in the previous response, as well as the module name (`my_module` in this case). + +```sh +module_id="0x9238689c6c14db84519686958643bf47de13e54e" +module_name="my_module" + +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_getNormalizedMoveModule\", \"params\": [\"$module_id\",\"$module_name\"]}" + +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, you get a response with the following shape: + +```JSON +{ + "jsonrpc": "2.0", + "result": { + "file_format_version": 5, + "address": "0x9238689c6c14db84519686958643bf47de13e54e", + "name": "my_module", + "friends": [], + "structs": { + "Forge": { + "abilities": { + "abilities": [ + "Key" + ] + }, + "type_parameters": [], + "fields": [ + { + "name": "id", + "type_": { + "Struct": { + "address": "0x2", + "module": "object", + "name": "UID", + "type_arguments": [] + } + } + }, + { + "name": "swords_created", + "type_": "U64" + } + ] + }, + "Sword": { + "abilities": { + "abilities": [ + "Store", + "Key" + ] + }, + "type_parameters": [], + "fields": [ + { + "name": "id", + "type_": { + "Struct": { + "address": "0x2", + "module": "object", + "name": "UID", + "type_arguments": [] + } + } + }, + { + "name": "magic", + "type_": "U64" + }, + { + "name": "strength", + "type_": "U64" + } + ] + } + }, + "exposed_functions": { + "magic": { + "visibility": "Public", + "is_entry": false, + "type_parameters": [], + "parameters": [ + { + "Reference": { + "Struct": { + "address": "0x9238689c6c14db84519686958643bf47de13e54e", + "module": "my_module", + "name": "Sword", + "type_arguments": [] + } + } + } + ], + "return_": [ + "U64" + ] + }, + "strength": { + "visibility": "Public", + "is_entry": false, + "type_parameters": [], + "parameters": [ + { + "Reference": { + "Struct": { + "address": "0x9238689c6c14db84519686958643bf47de13e54e", + "module": "my_module", + "name": "Sword", + "type_arguments": [] + } + } + } + ], + "return_": [ + "U64" + ] + }, + "sword_create": { + "visibility": "Public", + "is_entry": true, + "type_parameters": [], + "parameters": [ + { + "MutableReference": { + "Struct": { + "address": "0x9238689c6c14db84519686958643bf47de13e54e", + "module": "my_module", + "name": "Forge", + "type_arguments": [] + } + } + }, + "U64", + "U64", + "Address", + { + "MutableReference": { + "Struct": { + "address": "0x2", + "module": "tx_context", + "name": "TxContext", + "type_arguments": [] + } + } + } + ], + "return_": [] + }, + "swords_created": { + "visibility": "Public", + "is_entry": false, + "type_parameters": [], + "parameters": [ + { + "Reference": { + "Struct": { + "address": "0x9238689c6c14db84519686958643bf47de13e54e", + "module": "my_module", + "name": "Forge", + "type_arguments": [] + } + } + } + ], + "return_": [ + "U64" + ] + } + } + }, + "id": 1 +} +``` + +By design, the response contains a lot of useful information. The `structs` object has `Forge` and `Sword` objects, simulating an actual forge that is used to create swords. The `exposed_functions` field has the functions used in following examples, like `sword_create`, `magic`, and `strength`. To give your forge a task, mint a magic katana for yourself, because the good things must be kept in-house. The method is `sui_moveCall` and needs more than a few parameters to work. Time to bind them to variables and prepare the data to have a clearer overview: + +```sh +# Signer is our $address +# The package id +package_object_id="0x9238689c6c14db84519686958643bf47de13e54e" +module="my_module" +function="sword_create" +# The type arguments and arguments can be found in the previous result under the sword_create function +type_arguments="[]" +arguments="[\"0xeb8e4a532d09c596564f1c48b17f8ca4b339dbda\", \"455\", \"999\", \"$address\"]" + +# Dump all variables into the data object +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_moveCall\", \"params\": [\"$address\", \"$package_object_id\", \"$module\", \"$function\", $type_arguments, $arguments, \"$gas_id\", 10000]}" + +# Cross fingers and fire request +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +The requests should succeed. Before executing the transaction, let's take some time to recap the parameters of the request: + +- `package_object_id` is the address/UID of the package you published unto Sui. You can see it in the `sui_getNormalizedMoveModule` response in many places, most notably as the value of `address`, the second key of the `result` JSON object. +- `module` is the module name; this is needed because a package might contain more than one module. +- `function` is the name of the function to run. +- `type_arguments` is being given by the function itself. Checking the module with the `sui_getNormalizedMoveModule` method showed that under the `sword_create` JSON object, the `type_paramaters` key has value `[]`. Consequently, `[]` is the value passed with this call. +- `arguments` is another reference to the values from the response to the `sui_getNormalizedMoveModule` call. The `sword_create` function has a few parameters. The JSON-Move subset of JSON requires that arrays are homogenous. This `arguments` array contains only strings (as is usual for most arrays in JSON RPC requests). The first argument for the function is a `mutable reference to the Forge object`, this is encoded as `id of the object` so we just put the id of the Forge that has been created previously. `Magic` and `Strength`, as seen in the parameters field (inside the `sui_getNormalizedMoveModule` result) are both `U64` (unsigned integer 64 bits), but the request uses `\"455\"` and `\"999\"` as strings to create an homogenous array, relying on the Sui Node to translate into proper types. +- `TxContext` is the last required parameter. The quick-witted have already noticed that the parameter is omitted from the call, though. This is intentional as Sui fills in the value when it runs the function. This holds for any function that has `Mutable Reference TxContext` (or `&mut TxContext` in Move source code). + +The last two arguments are the usual arguments for gas deduction, `$gas_id` being the Coin object ID and `10000` being the gas budget value. + +Continuing, bind the `tx_bytes` value and execute the transaction. + +```sh +# Get txBytes from previous result +tx_bytes="VHJhbnNhY3Rpb25EYXRhOjoAApI4aJxsFNuEUZaGlYZDv0feE+VOAQAAAAAAAAAg+pryAo+gALTc0mDEz9wJ3XFmmJ4IMz131namNQmzj4MJbXlfbW9kdWxlDHN3b3JkX2NyZWF0ZQAEAQDrjkpTLQnFllZPHEixf4yksznb2gEAAAAAAAAAIIq8/a2erR0ImDILYDhh3kBL5EXVUkFo5TgCvFzOBhBqAAjHAQAAAAAAAAAI5wMAAAAAAAAAFPwIv478w9s2IYqaMV/2x6C/DT0S/Ai/jvzD2zYhipoxX/bHoL8NPRL6Ecj//u2x1EZIs53WLaU5X9U2ygIAAAAAAAAAIAM0VDf2JZIbgYIbHcUCdS/RZUWF7uxa1hVW98o9wzlcAQAAAAAAAAAQJwAAAAAAAA==" + +# Get the signature +sui keytool sign --address "$address" --data "$tx_bytes" + +signature="BXESHr1zl9p/oAegLcAwWQq/F6ljHg+a8N2+GOphlaW44GKJAvbGV6Zjs4E0Di0ZRb7O/9HrCzXY17WJU+7sDg==" + +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_executeTransaction\", \"params\": [\"$tx_bytes\", \"$scheme\",\"$signature\",\"$pub_key\",\"WaitForLocalExecution\"]}" + +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, you get a response representing ownership of your new katana: + +```JSON +// ... + "created": [ + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0x36e8443ea817223639ef6bdd5400d2bfa1b673f2", + "version": 1, + "digest": "To13qwyuk+zgFskF5aN8LOt4w7cHEosqZ89ZO354J80=" + } + } + ] +//... +``` + +You now have a sword with imba stats. In the next example, you send your sword to a friend (or generally speaking, another address on the ledger). \ No newline at end of file diff --git a/doc/src/explore/walkthrough/publish-package.md b/doc/src/explore/walkthrough/publish-package.md new file mode 100644 index 000000000000..06c769752f97 --- /dev/null +++ b/doc/src/explore/walkthrough/publish-package.md @@ -0,0 +1,91 @@ +--- +title: Publish a Package +--- + +Use the `sui_publish` method to publish packages, providing the necessary parameter values: +* `sender` - The transaction signer's Sui address. +* `compiled_modules` - The compiled bytes of a Move module. In this case, the response received in the previous call. +* `gas` - Gas object to use. +* `gas_budget`. The gas budget. + +As has become custom, bind the base64 response to a variable, making sure not to include the enclosing square brackets: + +```sh +# Bind the base64 output without the square brackets [] +module_base64="oRzrCwUAAAAKAQAIAggQAxgpBEEEBUUsB3F9CO4BKAqWAhIMqAJyDZoDBgAAAQEBAgEDAAQIAAAFDAADBgIAAQ0EAAAHAAEAAAgCAwAACQIDAAAKBAEAAAsFAwABDgAHAAMPCAkAAgIKAQEIBwYHCwEHCAIAAQYIAQEDBQcIAAMDBQcIAgEGCAABCAABCAMBBggCAQUCCQAFAQgBCW15X21vZHVsZQZvYmplY3QIdHJhbnNmZXIKdHhfY29udGV4dAVGb3JnZQVTd29yZAlUeENvbnRleHQEaW5pdAVtYWdpYwhzdHJlbmd0aAxzd29yZF9jcmVhdGUOc3dvcmRzX2NyZWF0ZWQCaWQDVUlEA25ldwZzZW5kZXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAICDAgDCwMBAgMMCAMIAwkDAAAAAAYLCgARBQYAAAAAAAAAABIADAELAQsALhEGOAACAQEAAAEECwAQABQCAgEAAAEECwAQARQCAwEEAAsSCwQRBQsBCwISAQwFCwULAzgBCgAQAhQGAQAAAAAAAAAWCwAPAhUCBAEAAAEECwAQAhQCAQEBAgABAA==" + +# Prepare the data +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_publish\", \"params\": [\"$address\", [\"$module_base64\"], \"$gas_id\", 10000]}" + +# Fire the request +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, the response includes a `txBytes` value: + +```JSON +{ + "jsonrpc": "2.0", + "result": { + "txBytes": "VHJhbnNhY3Rpb25EYXRhOjoAAQHMA6Ec6wsFAAAACgEACAIIEAMYKQRBBAVFLAdxfQjuASgKlgISDKgCcg2aAwYAAAEBAQIBAwAECAAABQwAAwYCAAENBAAABwABAAAIAgMAAAkCAwAACgQBAAALBQMAAQ4ABwADDwgJAAICCgEBCAcGBwsBBwgCAAEGCAEBAwUHCAADAwUHCAIBBggAAQgAAQgDAQYIAgEFAgkABQEIAQlteV9tb2R1bGUGb2JqZWN0CHRyYW5zZmVyCnR4X2NvbnRleHQFRm9yZ2UFU3dvcmQJVHhDb250ZXh0BGluaXQFbWFnaWMIc3RyZW5ndGgMc3dvcmRfY3JlYXRlDnN3b3Jkc19jcmVhdGVkAmlkA1VJRANuZXcGc2VuZGVyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgACAgwIAwsDAQIDDAgDCAMJAwAAAAAGCwoAEQUGAAAAAAAAAAASAAwBCwELAC4RBjgAAgEBAAABBAsAEAAUAgIBAAABBAsAEAEUAgMBBAALEgsEEQULAQsCEgEMBQsFCwM4AQoAEAIUBgEAAAAAAAAAFgsADwIVAgQBAAABBAsAEAIUAgEBAQIAAQD8CL+O/MPbNiGKmjFf9segvw09EunIWn9JwNBlJoVpDb1VL+F6g70uAwAAAAAAAAAgzMc4fVHWOg4vVMa8l1JM4erSJKxz7I8BlluS5dWKoZEBAAAAAAAAABAnAAAAAAAA" + //... + } + //... +} +``` + +Now to execute the transaction: + +```sh +# Usual binding +tx_bytes="VHJhbnNhY3Rpb25EYXRhOjoAAQHMA6Ec6wsFAAAACgEACAIIEAMYKQRBBAVFLAdxfQjuASgKlgISDKgCcg2aAwYAAAEBAQIBAwAECAAABQwAAwYCAAENBAAABwABAAAIAgMAAAkCAwAACgQBAAALBQMAAQ4ABwADDwgJAAICCgEBCAcGBwsBBwgCAAEGCAEBAwUHCAADAwUHCAIBBggAAQgAAQgDAQYIAgEFAgkABQEIAQlteV9tb2R1bGUGb2JqZWN0CHRyYW5zZmVyCnR4X2NvbnRleHQFRm9yZ2UFU3dvcmQJVHhDb250ZXh0BGluaXQFbWFnaWMIc3RyZW5ndGgMc3dvcmRfY3JlYXRlDnN3b3Jkc19jcmVhdGVkAmlkA1VJRANuZXcGc2VuZGVyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgACAgwIAwsDAQIDDAgDCAMJAwAAAAAGCwoAEQUGAAAAAAAAAAASAAwBCwELAC4RBjgAAgEBAAABBAsAEAAUAgIBAAABBAsAEAEUAgMBBAALEgsEEQULAQsCEgEMBQsFCwM4AQoAEAIUBgEAAAAAAAAAFgsADwIVAgQBAAABBAsAEAIUAgEBAQIAAQD8CL+O/MPbNiGKmjFf9segvw09EunIWn9JwNBlJoVpDb1VL+F6g70uAwAAAAAAAAAgzMc4fVHWOg4vVMa8l1JM4erSJKxz7I8BlluS5dWKoZEBAAAAAAAAABAnAAAAAAAA" + +# Get the signature +sui keytool sign --address "$address" --data "$tx_bytes" +# INFO sui::keytool: Address : 0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12 +# INFO sui::keytool: Flag Base64: AA== +# INFO sui::keytool: Public Key Base64: R904IKMQHbULGI+8g3aKNndZHcXbO3FSRoZF3QspcnY= +# INFO sui::keytool: Signature : 73nBz+KZ3ppddt/gc4KBWePE6maYlwgpIgqozSkd4V6HkyFJt2NRy/oD82to8HnlDzzDECNgATSM2YyNDx9fBw== + +# More biding +signature="73nBz+KZ3ppddt/gc4KBWePE6maYlwgpIgqozSkd4V6HkyFJt2NRy/oD82to8HnlDzzDECNgATSM2YyNDx9fBw==" + +# Prepare data +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_executeTransaction\", \"params\": [\"$tx_bytes\", \"$scheme\",\"$signature\",\"$pub_key\",\"WaitForLocalExecution\"]}" + +# Fire +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, you get a similar response: + +```JSON +{ + // ... + "created": [ + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0xeb8e4a532d09c596564f1c48b17f8ca4b339dbda", // Our new Forge object + "version": 1, + "digest": "Bp1deLh2HeD/m0CdW659evPsE8Hr/ynxQMGfFq9+Aaw=" + } + }, + { + "owner": "Immutable", + "reference": { + "objectId": "0x9238689c6c14db84519686958643bf47de13e54e", // Our new package + "version": 1, + "digest": "xXms6tXr52jaiHfCeVeUmgjTqPGWGrUan8cFzHjw3NA=" + } + } + ] + // ... +} +``` + +A new object and a new package appear on the Sui ledger. As the comments in the JSON point out, there is both a Forge object and a package. The package contains the functions to create swords and check them, while the package's `init` function created the Forge object. The `init` function runs only once, right after the bytecode is stored in Sui. + +With a Forge object now available, it's time to mint some swords to raise some mayhem! \ No newline at end of file diff --git a/doc/src/explore/walkthrough/split-coin.md b/doc/src/explore/walkthrough/split-coin.md new file mode 100644 index 000000000000..58348105b3d1 --- /dev/null +++ b/doc/src/explore/walkthrough/split-coin.md @@ -0,0 +1,299 @@ +--- +title: Split a SUI Coin object +--- + +In this example, you use the `sui_splitCoin` method to split one of your Coin objects into two objects: one with 9,999 SUI and another with 9,990,001 SUI. This is a transaction, as such it will require payment of gas. In this instance, you use another Coin object to pay for the gas (the same object will be used consistently for this purpose for future exercises). For demonstration, this example uses the object with ID `0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e`. + +Bind this id to a variable in your terminal (replacing the example ID with one of your object IDs, of course): + +```sh +gas_id="0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e" +``` +> **NOTE:** This same Coin object is used for future gas payments in following exercises. + +The parameters for the request payload are `signer`, `coin_object_id`, `split_amounts`, `gas`, and `gas_budget`, where `gas` is the Coin object to subtract gas from. For now, this example sets a large budget for the `gas_budget` parameter to make sure the transaction succeeds. Subsequent examples show how you can check the gas price reference to fine tune your transactions. + +This is the data to send with your curl request: + +```sh +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_splitCoin\", \"params\": [\"$address\", \"$id\", [9999], \"$gas_id\", 100000]}" +``` +With `data` set, run the curl command: +```sh +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, your response resembles the following: + +```JSON +{ + "jsonrpc": "2.0", + "result": { + "txBytes": "VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAg61Q+9Nb1tpyLqvfx3DAp0d2s+c64rNfj1WaiqXiqd08DcGF5CXNwbGl0X3ZlYwEHAAAAAAAAAAAAAAAAAAAAAAAAAAIDc3VpA1NVSQACAQCRvnssAREl90jDCIctAMjyAMq+FQEAAAAAAAAAIGbrG8PNNFpOPr6ZHovCUA/hCYkBH/D75nSEKJB8F9DdAAkBDycAAAAAAAD8CL+O/MPbNiGKmjFf9segvw09EunIWn9JwNBlJoVpDb1VL+F6g70uAQAAAAAAAAAgBptpMcUxbtjN0D9CGvtqSwS9odmEfW9pho+aIF/MiA4BAAAAAAAAAKCGAQAAAAAA", + "gas": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 1, + "digest": "BptpMcUxbtjN0D9CGvtqSwS9odmEfW9pho+aIF/MiA4=" + }, + "inputObjects": [ + { + "ImmOrOwnedMoveObject": { + "objectId": "0x91be7b2c011125f748c308872d00c8f200cabe15", + "version": 1, + "digest": "Zusbw800Wk4+vpkei8JQD+EJiQEf8PvmdIQokHwX0N0=" + } + }, + { + "MovePackage": "0x0000000000000000000000000000000000000002" + }, + { + "ImmOrOwnedMoveObject": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 1, + "digest": "BptpMcUxbtjN0D9CGvtqSwS9odmEfW9pho+aIF/MiA4=" + } + } + ] + }, + "id": 1 +} +``` + +This response might not quite be what you expected. The main point of this request is to get the transaction bytes that the virtual machine understands and can execute. This means our initial intent to split the Coin object is not yet realized. You now have the `tx_bytes` value, however, which you can supply to the [`sui_executeTransaction`](/sui-jsonrpc#sui_executeTransaction) method to perform the actual splitting. This is the standard procedure when using the RPC directly for any type of transaction that mutates objects (not a GET request). + +A review of the parameters needed for the `sui_executeTransaction` method shows some parameters that have not been introduced yet: `sig_scheme`, `signature`, `pub_key`, and `request_type`. Use the `sui keytool` command from the sui CLI. The exact command is `sui keytool sign --address --data `. + +```sh +# For clarity, bind the transactions bytes (txBytes) from the previous response to a variable +tx_bytes="VHJhbnNhY3Rpb25EYXRhOjoAAgAAAAAAAAAAAAAAAAAAAAAAAAACAQAAAAAAAAAg61Q+9Nb1tpyLqvfx3DAp0d2s+c64rNfj1WaiqXiqd08DcGF5CXNwbGl0X3ZlYwEHAAAAAAAAAAAAAAAAAAAAAAAAAAIDc3VpA1NVSQACAQCRvnssAREl90jDCIctAMjyAMq+FQEAAAAAAAAAIGbrG8PNNFpOPr6ZHovCUA/hCYkBH/D75nSEKJB8F9DdAAkBDycAAAAAAAD8CL+O/MPbNiGKmjFf9segvw09EunIWn9JwNBlJoVpDb1VL+F6g70uAQAAAAAAAAAgBptpMcUxbtjN0D9CGvtqSwS9odmEfW9pho+aIF/MiA4BAAAAAAAAAKCGAQAAAAAA" + +sui keytool sign --address "$address" --data "$tx_bytes" +# INFO sui::keytool: Address : 0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12 +# INFO sui::keytool: Flag Base64: AA== +# INFO sui::keytool: Public Key Base64: R904IKMQHbULGI+8g3aKNndZHcXbO3FSRoZF3QspcnY= +# INFO sui::keytool: Signature : 6LARTREvuT81FxtJPUI9XqoWLlNUTc3yg3yG6i3va3XhDi9WlIgu1ZXmC88VUD3fMeW5EUOh81DU8bLILXoTBw== +``` +The `sig_scheme` is the digital signature scheme you chose at address creation, which is `ED25519` by default. + +The `request_type` value can be one of `ImmediateReturn`, `WaitForTxCert`, `WaitForEffectsCert`, `WaitForLocalExecution`. The value provided sets how much information is returned by the response. Although everything on the Sui network happens very fast, you could submit a value of `ImmediateReturn` if you are programmatically in a hurry to favor response time over information returned. For this exercise, set the value to `WaitForLocalExecution` to return the complete set of information. + +With all the necessary parameter values known, it's time to execute the transaction: + +```sh +# Bind data to variables +signature="6LARTREvuT81FxtJPUI9XqoWLlNUTc3yg3yG6i3va3XhDi9WlIgu1ZXmC88VUD3fMeW5EUOh81DU8bLILXoTBw==" +scheme="ED25519" +pub_key="R904IKMQHbULGI+8g3aKNndZHcXbO3FSRoZF3QspcnY=" + +# Form the payload +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_executeTransaction\", \"params\": [\"$tx_bytes\", \"$scheme\",\"$signature\",\"$pub_key\",\"WaitForLocalExecution\"]}" + +# Fire the request +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, the response is long and verbose: + +```JSON +{ + "jsonrpc": "2.0", + "result": { + "EffectsCert": { + "certificate": { + "transactionDigest": "PEGLG0dsS+4qPX6Qu77l2HauyB3eKsTfZoLExPp0GfU=", + "data": { + "transactions": [ + { + "Call": { + "package": { + "objectId": "0x0000000000000000000000000000000000000002", + "version": 1, + "digest": "61Q+9Nb1tpyLqvfx3DAp0d2s+c64rNfj1WaiqXiqd08=" + }, + "module": "pay", + "function": "split_vec", + "typeArguments": [ + "0x2::sui::SUI" + ], + "arguments": [ + "0x91be7b2c011125f748c308872d00c8f200cabe15", + [ + 9999 + ] + ] + } + } + ], + "sender": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12", + "gasPayment": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 1, + "digest": "BptpMcUxbtjN0D9CGvtqSwS9odmEfW9pho+aIF/MiA4=" + }, + "gasBudget": 100000 + }, + "txSignature": "AOiwEU0RL7k/NRcbST1CPV6qFi5TVE3N8oN8huot72t14Q4vVpSILtWV5gvPFVA93zHluRFDofNQ1PGyyC16EwdH3TggoxAdtQsYj7yDdoo2d1kdxds7cVJGhkXdCylydg==", + "authSignInfo": { + "epoch": 0, + "signature": "kU/ZpPuirQw+UzEE2FjsAdQD70SMEYF67S0DZR2yy5Ns673/ws/RbOM8uSm3wkhQ", + "signers_map": [ + 58, + 48, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 16, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 3, + 0 + ] + } + }, + "effects": { + "transactionEffectsDigest": "asC3MKdc8nDhlkeMthWiSZdRRNOq4Gi0bZijA+Nlu3Y=", + "effects": { + "status": { + "status": "success" + }, + "gasUsed": { + "computationCost": 557, + "storageCost": 45, + "storageRebate": 30 + }, + "transactionDigest": "PEGLG0dsS+4qPX6Qu77l2HauyB3eKsTfZoLExPp0GfU=", + "created": [ + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0x0f848b589fe7727a628359c26bf880c9efb1de3b", + "version": 1, + "digest": "FmBwMRf+r1QlTf3XXBYizElY++W4w19tjeSLmTDpgbI=" + } + } + ], + "mutated": [ + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0x91be7b2c011125f748c308872d00c8f200cabe15", + "version": 2, + "digest": "fVd5rvaR2AafWKtjLO1nemS6Qqs1xnrHPk0RStbPK50=" + } + }, + { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 2, + "digest": "w0PcNy/0pKEieoWQ/4lFx8XaomMnotSltRZMMMd4KtI=" + } + } + ], + "gasObject": { + "owner": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "reference": { + "objectId": "0xe9c85a7f49c0d0652685690dbd552fe17a83bd2e", + "version": 2, + "digest": "w0PcNy/0pKEieoWQ/4lFx8XaomMnotSltRZMMMd4KtI=" + } + }, + "events": [ + { + "newObject": { + "packageId": "0x0000000000000000000000000000000000000002", + "transactionModule": "pay", + "sender": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12", + "recipient": { + "AddressOwner": "0xfc08bf8efcc3db36218a9a315ff6c7a0bf0d3d12" + }, + "objectId": "0x0f848b589fe7727a628359c26bf880c9efb1de3b" + } + } + ], + "dependencies": [ + "B2015vW4kYmFXLsBw/njGWUOQHdmszg8jsdygrUFTPw=", + "lBnZ6OXExGfd0C5EzCLlR2gXAT/aTn0EnOvwF5KJEOU=" + ] + }, + "authSignInfo": { + "epoch": 0, + "signature": "gp4NdTfonxPet2v+v2gdEmBhLs7Ii7zZ6UmSjKvuv8h7KxFtWZaMqVamk9QXiL9f", + "signers_map": [ + 58, + 48, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 16, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 3, + 0 + ] + } + }, + "confirmed_local_execution": true + } + }, + "id": 1 +} +``` + +The `effects` object shows the transaction was successful. There is now a mutated object with the ID of the initial coin. The `version` value got bumped up to `2` to signal the object has experienced two transactions: this one and the creation of the object. There is also a newly created object with ID `0x0f848b589fe7727a628359c26bf880c9efb1de3b==`. + +If you check your new object with `sui_getObject`, you should get a response similar to: + +```JSON +"result": { + "status": "Exists", + "details": { + "data": { + "dataType": "moveObject", + "type": "0x2::coin::Coin<0x2::sui::SUI>", + "has_public_transfer": true, + "fields": { + "balance": 9999, + "id": { + "id": "0x0f848b589fe7727a628359c26bf880c9efb1de3b==" + } + } + }, // ... + } // ... +} +``` +The response confirms the existence of a Coin object with 9,999 worth of SUI. If you check all your owned objects (first example), you can see the other two coins that changed, one with balance `9990001` SUI and the other with `9999428` SUI. The latter is the one that was used to pay for the gas. + +The next example explores the other `request_type` values and shows how to subscribe to events so you know what's happening with your transactions. \ No newline at end of file diff --git a/doc/src/explore/walkthrough/transfer-objects.md b/doc/src/explore/walkthrough/transfer-objects.md new file mode 100644 index 000000000000..87bf6a0cd206 --- /dev/null +++ b/doc/src/explore/walkthrough/transfer-objects.md @@ -0,0 +1,59 @@ +--- +title: Transfer Objects +--- + +The last example involves transferring the magic katana created previously to another address. The method to do so is `sui_transferObject`. + +The methods are fairly straightforward and similar to `sui_splitCoin` used in a previous example. You need a recipient address, someone else's or a second address of your own. + + +```sh +# Address who will receive the stuff +friend_address="0x788a511738ad4ab1d7f769b49076d9c7b272826c" + +# The id of the Sword NFT +sword_id="0x36e8443ea817223639ef6bdd5400d2bfa1b673f2" + +# Prepare the data params: [, , , , ] +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_transferObject\", \"params\": [\"$address\", \"$sword_id\", \"$gas_id\", 10000, \"$friend_address\"]}" + +# Send our transaction to be validated +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json + +# Get the tx_bytes +tx_bytes="VHJhbnNhY3Rpb25EYXRhOjoAAHiKURc4rUqx1/dptJB22ceycoJsNuhEPqgXIjY572vdVADSv6G2c/IBAAAAAAAAACBOjXerDK6T7OAWyQXlo3ws63jDtwcSiypnz1k7fngnzfwIv478w9s2IYqaMV/2x6C/DT0S+hHI//7tsdRGSLOd1i2lOV/VNsoDAAAAAAAAACDh08xwMUIlEXznVO/kW9uVptN+cK351OvieMgvhlB3vgEAAAAAAAAAECcAAAAAAAA=" + +# Get the signature +sui keytool sign --address "$address" --data "$tx_bytes" + +signature="LXDnYcjFQU6boMyp+ZBbeYr1dSjcwjnXu9mEtu/yDApf/edHyNzUT4xGW6umDnc7IW539qP04wihrkyjKVF1CA==" +pub_key="R904IKMQHbULGI+8g3aKNndZHcXbO3FSRoZF3QspcnY=" +scheme="ED25519" + +# Data for the execution +data="{\"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"sui_executeTransaction\", \"params\": [\"$tx_bytes\", \"$scheme\",\"$signature\",\"$pub_key\",\"WaitForLocalExecution\"]}" + +# Say goodbye to your sword: +curl -X POST -H 'Content-type: application/json' --data-raw "$data" $rpc > result.json +``` + +If successful, the response confirms transfer: + +```JSON +//... +"mutated": [ + { + "owner": { + "AddressOwner": "0x788a511738ad4ab1d7f769b49076d9c7b272826c" + }, + "reference": { + "objectId": "0x36e8443ea817223639ef6bdd5400d2bfa1b673f2", + "version": 2, + "digest": "oNqMlWH+Eslz+7ZLVtEKddWw1UlPmPj0tQAwWRoRzYg=" + } + }, //... +] +//... +``` + +The `AddressOwner` is your `$friend_address` for the sword (`object_id` same as `$sword_id`). Also, the sword's version got bumped up to 2, meaning it has experienced two transactions: first transaction being its forging (actually, it's the transfer to our address after creation, if you check the source code for the [`sword_create`](https://github.com/MystenLabs/sui/blob/main/sui_programmability/examples/move_tutorial/sources/my_module.move) function), and the second transaction is the transfer you just initiated. \ No newline at end of file diff --git a/doc/src/explore/walkthrough/working-with-move-packages.md b/doc/src/explore/walkthrough/working-with-move-packages.md new file mode 100644 index 000000000000..5927b2496dcb --- /dev/null +++ b/doc/src/explore/walkthrough/working-with-move-packages.md @@ -0,0 +1,42 @@ +--- +title: Interlude +--- + +Now might be a good time to head out to the lobby and grab yourself a snack. When you return, start the next examples that involve publishing and using a Move module on the blockchain. In the interest of time, these examples use a sample module rather than creating one from scratch. To learn more about Move and how to write modules suitable for Sui, check out [examples.sui.io](http://examples.sui.io/). + +To get the necessary Move package, clone the Sui repo. The module to explore is `move_tutorial` located in the `sui/sui_programmability/examples` directory. + +```sh +# clone the repo in the work or home directory +git clone https://github.com/MystenLabs/sui.git +``` + +You must first build modules before you can publish them. If you try to publish as is, you get an error. To get ahead of that situation, alter the `Move.toml` file inside `sui/sui_programmability/examples/move_tutorial/`. Change the following line: + +``` +[dependencies] +Sui = { local = "../../../crates/sui-framework" } +``` + +to + +``` +[dependencies] +Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework", rev = "devnet" } +``` + +Also, at the end of the `Move.toml` file add the following line: + +``` +sui = "0000000000000000000000000000000000000002" +``` + +Now the module is ready to be built. Inside the `sui/sui_programmability/examples/move_tutorial/` directory, run: + +```sh +# Inside sui/sui_programmability/examples/move_tutorial/ +sui move build --dump-bytecode-as-base64 +# ["oRzrCwUAAAAKAQAIAggQAxgpBEEEBUUsB3F9CO4BKAqWAhIMqAJyDZoDBgAAAQEBAgEDAAQIAAAFDAADBgIAAQ0EAAAHAAEAAAgCAwAACQIDAAAKBAEAAAsFAwABDgAHAAMPCAkAAgIKAQEIBwYHCwEHCAIAAQYIAQEDBQcIAAMDBQcIAgEGCAABCAABCAMBBggCAQUCCQAFAQgBCW15X21vZHVsZQZvYmplY3QIdHJhbnNmZXIKdHhfY29udGV4dAVGb3JnZQVTd29yZAlUeENvbnRleHQEaW5pdAVtYWdpYwhzdHJlbmd0aAxzd29yZF9jcmVhdGUOc3dvcmRzX2NyZWF0ZWQCaWQDVUlEA25ldwZzZW5kZXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAICDAgDCwMBAgMMCAMIAwkDAAAAAAYLCgARBQYAAAAAAAAAABIADAELAQsALhEGOAACAQEAAAEECwAQABQCAgEAAAEECwAQARQCAwEEAAsSCwQRBQsBCwISAQwFCwULAzgBCgAQAhQGAQAAAAAAAAAWCwAPAhUCBAEAAAEECwAQAhQCAQEBAgABAA=="] +``` + +If you receive an error, you might need to update your Sui client. Follow the instructions the Sui client displays in your terminal to update. \ No newline at end of file