Skip to content

Commit c277457

Browse files
committed
final touch - Smart contract interactions
1 parent 585226c commit c277457

File tree

1 file changed

+58
-37
lines changed

1 file changed

+58
-37
lines changed

docs/sdk-and-tools/mxpy/smart-contract-interactions.md

Lines changed: 58 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ title: Smart contract interactions
55

66
[comment]: # (mx-abstract)
77

8-
Let's dive deeper into the Smart Contract interactions and what do you need to know when you need to interact with a SC. If you followed the [previous `mxpy`](/docs/sdk-and-tools/mxpy/mxpy-cli.md) related documentation, you should be able to set up your prerequisites like proxy URL, the chain ID and the PEM file.
8+
Let's dive deeper into smart contract interactions and what you need to know to interact with a contract. If you followed the [previous `mxpy`](/docs/sdk-and-tools/mxpy/mxpy-cli.md) related documentation, you should be able to set up your prerequisites like proxy URL, the chain ID and the PEM file.
99

10-
For this, we need a file inside the contract's folder, with a suggestive name. For example: **devnet.snippets.sh**.
10+
For this, we need a file inside the contract's folder, with a suggestive name. For example: `devnet.snippets.sh`.
1111

1212
:::important
13-
In order to be able to call methods from the file, we need to assign the shell file as a source file in the terminal. We can do this by running the `source devnet.snippets.sh` command. Also, after each change to the interactions file, we need to repeat the source command.
13+
In order to be able to call methods from the file, we need to assign the shell file as a source file in the terminal. We can do this by running the next command:
14+
15+
```shell
16+
source devnet.snippets.sh
17+
```
18+
19+
After each change to the interactions file, we need to repeat the source command.
1420
:::
1521

1622
Let's take the following example:
@@ -25,18 +31,23 @@ Let's take the following example:
2531

2632
## Prerequisites
2733

28-
:::important
2934
Before starting this tutorial, make sure you have the following:
3035

3136
- [`mxpy`](/sdk-and-tools/mxpy/mxpy-cli). Follow the [installation guide](/sdk-and-tools/mxpy/installing-mxpy) - make sure to use the latest version available.
32-
- `stable` **Rust** version `≥ 1.85.0`. Follow the [installation guide](/docs/developers/toolchain-setup.md#installing-rust-and-sc-meta).
33-
- `sc-meta` (install [multiversx-sc-meta](/docs/developers/meta/sc-meta-cli.md))
37+
- `stable` **Rust** version `≥ 1.83.0`. Follow the [installation guide](/docs/developers/toolchain-setup.md#installing-rust-and-sc-meta).
38+
- `sc-meta` (install [multiversx-sc-meta](/docs/developers/meta/sc-meta-cli.md)).
3439

35-
:::
40+
[comment]: # (mx-context-auto)
3641

3742
## Deploy
3843

39-
First things first. In order to deploy a new contract, we need to use **sc-meta** to build it, in the contract root, by invoking `sc-meta all build`. This will output the WASM bytecode, to be used within the interactions file:
44+
First things first. In order to deploy a new contract, we need to use `sc-meta` to build it, in the contract root, by invoking the next command:
45+
46+
```shell
47+
sc-meta all build
48+
```
49+
50+
This will output the WASM bytecode, to be used within the interactions file:
4051

4152
```shell
4253
WASM_PATH="~/my-contract/output/my-contract.wasm"
@@ -58,21 +69,24 @@ deploySC() {
5869
--arguments $1 $2 \
5970
--send || return
6071
}
61-
62-
deploySC $1 $2
6372
```
6473

65-
Run in terminal the following command to deploy the smart contract on Devnet:
74+
Run in terminal the following command to deploy the smart contract on Devnet. Replace `arg1` and `arg2` with your desired deployment values.
6675

6776
```shell
6877
source devnet.snippets.sh
78+
deploySC arg1 arg2
6979
```
7080

71-
Now let's look at the structure of the interaction. It receives the path of the **wasm** file, where we previously built the contract. It also receives the path of the **wallet** (the PEM file), the **proxy URL** and the **chain ID**, where the contract will be deployed. Another important parameter is the **gas limit**, where we state the maximum amount of gas we are willing to spend with this transaction. Each transaction cost depends on its complexity and the amount of data storage it handles.
81+
Now let's look at the structure of the interaction. It receives the path of the **wasm file**, where we previously built the contract. It also receives the path of the **wallet** (the PEM file), the **proxy URL** and the **chain ID**, where the contract will be deployed. Another important parameter is the **gas limit**, where we state the maximum amount of gas we are willing to spend with this transaction. Each transaction cost depends on its complexity and the amount of data storage it handles.
7282

7383
Other than this, we also have the **arguments** keyword, that allows us to pass in the required parameters. As we previously said, deploying a smart contract means that we run the **init** function, which may or may not request some parameters. In our case, the **init** function has two different arguments, and we pass them when calling the **deploy** function. We'll come back later in this section at how we can pass parameters in function calls.
7484

75-
After the transaction is sent, `mxpy` will output information like the transaction hash, data and any other important information, based on the type of transaction. In case of a contract deployment, it will also output the newly deployed contract address.
85+
After the transaction is sent, `mxpy` will output information like the **transaction hash**, **data** and any other important information, based on the type of transaction. In case of a contract deployment, it will also output the newly deployed contract address.
86+
87+
[comment]: # (mx-context-auto)
88+
89+
## Upgrade
7690

7791
Let's now suppose we need to make the contract **payable**, in case it needs to receive funds. We could redeploy the contract but that will mean two different contracts, and not to mention that we will lose any existing storage. For that, we can use the **upgrade** command, that replaces the existing SC bytecode with the newly built contract version.
7892

@@ -94,11 +108,12 @@ upgradeSC() {
94108
--arguments $1 $2 \
95109
--send || return
96110
}
97-
98-
upgradeSC $1 $2
99111
```
100112

101-
Here we have 2 new different elements that we need to observe. First, we changed the **deploy** function with the **upgrade** function, which in turn requires the address of the previously deployed SC address, in order to be able to identify what SC to upgrade. Is important to note that this function can only be called by the SC's owner. The second element we need to observe is the **metadata-payable** keyword, which represents a [code metadata](/docs/developers/data/code-metadata.md) flag that allows the SC to receive payments.
113+
Here we have 2 new different elements that we need to observe:
114+
115+
1. We changed the **deploy** function with the **upgrade** function. This new function requires the address of the previously deployed smart contract so the system can identify which contract to update. It is important to note that this function can only be called by the smart contract's owner.
116+
2. The **metadata-payable** keyword, which represents a [code metadata](/docs/developers/data/code-metadata.md) flag that allows the smart contract to receive payments.
102117

103118
[comment]: # (mx-context-auto)
104119

@@ -108,8 +123,8 @@ Let's suppose we want to call the following endpoint, that receives an address a
108123

109124
```shell
110125
###PARAMS
111-
#1 - FirstBigUintArgument
112-
#2 - SecondBigUintArgument
126+
# $1 = FirstBigUintArgument
127+
# $2 = SecondBigUintArgument
113128
THIRD_BIGUINT_ARGUMENT=0x0f4240
114129
ADDRESS_ARGUMENT=addr:erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49swp3
115130

@@ -123,23 +138,26 @@ myNonPayableEndpoint() {
123138
--arguments $address_argument $1 $2 ${THIRD_BIGUINT_ARGUMENT}\
124139
--send || return
125140
}
126-
127-
myNonPayableEndpoint $1 $2
128141
```
129142

130-
So, what happens in this interaction and how do we call it? Besides the function and arguments parts, the snippet is more or less the same as when deploying or upgrading a contract. When calling a non payable function, we need to provide the endpoint's name as the function argument. As for the arguments, they have to be in the **same order** as in the SC, including when calling an endpoint that has a variable number of arguments. Now, for the sake of example, we provided the arguments in multiple ways. It is up to each developer to choose the layout he prefers, but a few points need to be underlined:
143+
So, what happens in this interaction and how do we call it?
131144

132-
- Most of the supplied **arguments** need to be in the **hex format**: `0x...`.
133-
- When converting a value to a hex format, we need to make sure it has an **even number** of characters. If not, we need to provide an extra 0 in order to make it even. (e.g. The number 911 -> In hex encoding, it is equal to: 38f -> So we need to provide the argument 0x038f).
145+
Besides the function and arguments parts, the snippet is more or less the same as when deploying or upgrading a contract. When calling a non payable function, we need to provide the endpoint's name as the function argument. As for the arguments, they have to be in the **same order** as in the smart contract, including when calling an endpoint that has a variable number of arguments. Now, for the sake of example, we provided the arguments in multiple ways.
146+
147+
It is up to each developer to choose the layout he prefers, but a few points need to be underlined:
148+
149+
- Most of the supplied **arguments** need to be in the **hexadecimal format**: `0x...`.
150+
- When converting a value to a hexadecimal format, we need to make sure it has an **even number** of characters. If not, we need to provide an extra `0` in order to make it even:
151+
- Example: the number `911` -> in hexadecimal encoding, it is equal to: `38f` -> so we need to provide the argument `0x038f`.
134152
- Arguments can be provided both as a fixed arguments (usually for unchangeable arguments like the contract's address or a fixed number) or can be provided as an input in the terminal, when interacting with the snippet (mostly used for arguments that change often like numbers).
135153

136-
In our example we provide the address argument as a fixed argument. We then convert it to hex format (as it is in the bech32 format by default) and only after that we pass it as a parameter. As for the `BigUint` parameters, we provide the first two parameters directly in the terminal and the last one as a fixed argument, hex encoded.
154+
In our example we provide the address argument as a fixed argument. We then convert it to hexadecimal format (as it is in the bech32 format by default) and only after that we pass it as a parameter. As for the `BigUint` parameters, we provide the first two parameters directly in the terminal and the last one as a fixed argument, hexadecimal encoded.
137155

138156
:::tip
139157
`mxpy` facilitates us with some encoding conventions, including:
140158

141-
- We can use **str:** for encoding strings. For example: `str:MYTOKEN-123456`.
142-
- Blockchain addresses that start with **erd1** are automatically encoded, so there is no need to further hex encode them.
159+
- We can use `str:` for encoding strings. For example: `str:MYTOKEN-123456`.
160+
- Blockchain addresses that start with `erd1` are automatically encoded, so there is no need to further hex encode them.
143161
- The values **true** or **false** are automatically converted to **boolean** values.
144162
- Values that are identified as **numbers** are hex encoded by default.
145163
- Arguments like `0x...` are left unchanged, as they are interpreted as already encoded hex values.
@@ -149,10 +167,9 @@ In our example we provide the address argument as a fixed argument. We then conv
149167
So, in case of our **myNonPayableEndpoint** interaction, we can write it like so:
150168

151169
```shell
152-
153170
###PARAMS
154-
#1 - FirstBigUintArgument
155-
#2 - SecondBigUintArgument
171+
# $1 = FirstBigUintArgument
172+
# $2 = SecondBigUintArgument
156173
THIRD_BIGUINT_ARGUMENT=1000000
157174
ADDRESS_ARGUMENT=addr:erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49swp3
158175

@@ -170,6 +187,7 @@ myNonPayableEndpoint() {
170187
A call example for this endpoint would look like:
171188

172189
```shell
190+
source devnet.snippets.sh
173191
myNonPayableEndpoint 10000 100000
174192
```
175193

@@ -208,7 +226,7 @@ myPayableEndpoint() {
208226
}
209227
```
210228

211-
As we can see, the way we call a **payable endpoint** is by calling an `ESDTTransfer` function (or any other function that transfer assets and supports contract calls) and providing the name of the method as an argument. The order of the arguments differs for each transfer function. In our case, we specify in the terminal the **token type** and **the amount of tokens** we want to transfer and then we provide as a **fixed input** what SC function we want to call.
229+
As we can see, the way we call a **payable endpoint** is by calling an `ESDTTransfer` function (or any other function that transfer assets and supports contract calls) and providing the name of the method as an argument. The order of the arguments differs for each transfer function. In our case, we specify in the terminal the **token type** and **the amount of tokens** we want to transfer and then we provide as a **fixed input** what smart contract endpoint we want to call.
212230

213231
[comment]: # (mx-context-auto)
214232

@@ -222,7 +240,6 @@ Now let's suppose we want to call an endpoint that accepts an NFT or an SFT as p
222240
# $2 = NFT/SFT Token Nonce,
223241
# $3 = NFT/SFT Token Amount,
224242
# $4 = Destination Address,
225-
226243
FIRST_BIGUINT_ARGUMENT=1000
227244
SECOND_BIGUINT_ARGUMENT=10000
228245
MY_WALLET_ADDRESS=erd1...
@@ -249,7 +266,11 @@ myESDTNFTPayableEndpoint() {
249266
}
250267
```
251268

252-
First of all, to call this type of transfer function we need to pass the receiver address the same as the sender address. So in this example, `MY_WALLET_ADDRESS` is the caller's address of the PEM wallet used. Now, like in the case of `ESDTTransfer`, the name of the called function is `ESDTNFTTransfer`. All the other required data is passed as arguments (including the destination contract's address and the endpoint). In case of this single NFT/SFT transfer, we first pass the **token** (identifier, nonce and amount) and then we pass the **destination address** and the **name of the endpoint**. In the end we pass whatever parameters the indicated method needs.
269+
First of all, to call this type of transfer function we need to pass the receiver address the same as the sender address. So in this example, `MY_WALLET_ADDRESS` is the caller's address of the PEM wallet used.
270+
271+
Now, like in the case of `ESDTTransfer`, the name of the called function is `ESDTNFTTransfer`. All the other required data is passed as arguments (including the destination contract's address and the endpoint).
272+
273+
In case of this single NFT/SFT transfer, we first pass the **token** (identifier, nonce and amount) and then we pass the **destination address** and the **name of the endpoint**. In the end we pass whatever parameters the indicated method needs.
253274

254275
[comment]: # (mx-context-auto)
255276

@@ -268,9 +289,9 @@ In case we need to call an endpoint that accepts multiple tokens (let's say for
268289
# $6 = Third Token Identifier,
269290
# $7 = Third Token Nonce,
270291
# $8 = Third Token Identifier,
271-
272292
FIRST_BIGUINT_ARGUMENT=1000
273293
SECOND_BIGUINT_ARGUMENT=10000
294+
274295
myMultiESDTNFTPayableEndpoint() {
275296
method_name=str:myMultiESDTPayableEndpoint
276297
destination_address=addr:$1
@@ -310,7 +331,7 @@ myMultiESDTNFTPayableEndpoint() {
310331

311332
In this example, we call `myMultiESDTPayableEndpoint` endpoint, by transferring **3 different tokens**: the first two are fungible tokens and the last one is an NFT.
312333

313-
The endpoint takes 2 BigUInt arguments. The layout of the snippet is almost the same as with **ESDTNFTTransfer** (including the fact that the sender is the same as the receiver) but has different arguments. We now pass the destination address first and the number of ESDT/NFT tokens that we want to sent. Then, for each sent token, we specify the identifier, the nonce (in our example 0 for the fungible tokens and a specific value for the NFT) and the amount. In the end, like with the **ESDTTransfer**, we pass the name of the method we want to call and the rest of the parameters of that specific method.
334+
The endpoint takes 2 BigUInt arguments. The layout of the snippet is almost the same as with `ESDTNFTTransfer` (including the fact that the sender is the same as the receiver) but has different arguments. We now pass the destination address first and the number of ESDT/NFT tokens that we want to sent. Then, for each sent token, we specify the identifier, the nonce (in our example 0 for the fungible tokens and a specific value for the NFT) and the amount. In the end, like with the `ESDTTransfer`, we pass the name of the method we want to call and the rest of the parameters of that specific method.
314335

315336
:::tip
316337
More information about ESDT Transfers [here](/tokens/fungible-tokens/#transfers).
@@ -323,10 +344,10 @@ More information about ESDT Transfers [here](/tokens/fungible-tokens/#transfers)
323344
In case we want to call a view function, we can use the **query** keyword.
324345

325346
```shell
326-
327347
###PARAMS
328-
#1 - First argument
329-
#2 - Second argument
348+
# $1 = First argument
349+
# $2 = Second argument
350+
330351
myView() {
331352
mxpy --verbose contract query ${CONTRACT_ADDRESS} \
332353
--proxy=${PROXY} \

0 commit comments

Comments
 (0)