Skip to content

Commit cd20fc6

Browse files
committed
apply reviews
1 parent b3a82cb commit cd20fc6

File tree

1 file changed

+61
-96
lines changed

1 file changed

+61
-96
lines changed

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

Lines changed: 61 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ After each change to the interactions file, we need to repeat the source command
2121

2222
Let's take the following example:
2323

24-
1. We want to deploy a new smart contract on the Devnet.
25-
2. We then need to upgrade the contract, to make it payable.
26-
3. We call an endpoint without transferring any assets.
27-
4. We make an `ESDTTransfer`, in order to call a payable endpoint.
28-
5. We call a view function.
24+
1. We want to **deploy** a new smart contract on the Devnet.
25+
2. We then need to **upgrade** the contract, to make it payable.
26+
3. We **call** an endpoint without transferring any assets.
27+
4. We **transfer** ESDT, in order to call a payable endpoint.
28+
5. We call a **view** function.
2929

3030
[comment]: # (mx-context-auto)
3131

@@ -35,7 +35,7 @@ Before starting this tutorial, make sure you have the following:
3535

3636
- [`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.
3737
- `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)).
38+
- `sc-meta`. Follow the [installation guide](/docs/developers/toolchain-setup.md#installing-rust-and-sc-meta).
3939

4040
[comment]: # (mx-context-auto)
4141

@@ -58,14 +58,12 @@ Now, in order to deploy the contract, we use the special **deploy** function of
5858
```shell
5959
WALLET_PEM="~/my-wallet/my-wallet.pem"
6060
PROXY="https://devnet-gateway.multiversx.com"
61-
CHAIN_ID="D"
6261

6362
deploySC() {
6463
mxpy --verbose contract deploy \
6564
--bytecode=${WASM_PATH} \
6665
--pem=${WALLET_PEM} \
67-
--gas-limit=60000000 \
68-
--proxy=${PROXY} --chain=${CHAIN_ID} \
66+
--proxy=${PROXY} \
6967
--arguments $1 $2 \
7068
--send || return
7169
}
@@ -78,11 +76,11 @@ source devnet.snippets.sh
7876
deploySC arg1 arg2
7977
```
8078

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.
79+
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) and the **proxy URL** where the contract will be deployed.
8280

8381
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.
8482

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.
83+
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**.
8684

8785
[comment]: # (mx-context-auto)
8886

@@ -103,13 +101,14 @@ upgradeSC() {
103101
mxpy --verbose contract upgrade ${CONTRACT_ADDRESS} --metadata-payable \
104102
--bytecode=${WASM_PATH} \
105103
--pem=${WALLET_PEM} \
106-
--gas-limit=60000000 \
107-
--proxy=${PROXY} --chain=${CHAIN_ID} \
104+
--proxy=${PROXY} \
108105
--arguments $1 $2 \
109106
--send || return
110107
}
111108
```
112109

110+
`CONTRACT_ADDRESS` is a placeholder value which value needs to be replaced with the address previously generated in the deploy action.
111+
113112
Here we have 2 new different elements that we need to observe:
114113

115114
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.
@@ -126,14 +125,13 @@ Let's suppose we want to call the following endpoint, that receives an address a
126125
# $1 = FirstBigUintArgument
127126
# $2 = SecondBigUintArgument
128127
THIRD_BIGUINT_ARGUMENT=0x0f4240
129-
ADDRESS_ARGUMENT=addr:erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49swp3
128+
ADDRESS_ARGUMENT=erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49swp3
130129

131130
myNonPayableEndpoint() {
132131
address_argument="0x$(mxpy wallet bech32 --decode ${ADDRESS_ARGUMENT})"
133132
mxpy --verbose contract call ${CONTRACT_ADDRESS} \
134133
--pem=${WALLET_PEM} \
135-
--gas-limit=6000000 \
136-
--proxy=${PROXY} --chain=${CHAIN_ID} \
134+
--proxy=${PROXY} \
137135
--function="myNonPayableEndpoint" \
138136
--arguments $address_argument $1 $2 ${THIRD_BIGUINT_ARGUMENT}\
139137
--send || return
@@ -142,7 +140,7 @@ myNonPayableEndpoint() {
142140

143141
So, what happens in this interaction and how do we call it?
144142

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.
143+
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.
146144

147145
It is up to each developer to choose the layout he prefers, but a few points need to be underlined:
148146

@@ -159,7 +157,7 @@ In our example we provide the address argument as a fixed argument. We then conv
159157
- We can use `str:` for encoding strings. For example: `str:MYTOKEN-123456`.
160158
- Blockchain addresses that start with `erd1` are automatically encoded, so there is no need to further hex encode them.
161159
- The values **true** or **false** are automatically converted to **boolean** values.
162-
- Values that are identified as **numbers** are hex encoded by default.
160+
- Values that are identified as **numbers** are hex encoded as `BigUint` values.
163161
- Arguments like `0x...` are left unchanged, as they are interpreted as already encoded hex values.
164162

165163
:::
@@ -176,8 +174,7 @@ ADDRESS_ARGUMENT=addr:erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49
176174
myNonPayableEndpoint() {
177175
mxpy --verbose contract call ${CONTRACT_ADDRESS} \
178176
--pem=${WALLET_PEM} \
179-
--gas-limit=6000000 \
180-
--proxy=${PROXY} --chain=${CHAIN_ID} \
177+
--proxy=${PROXY} \
181178
--function="myNonPayableEndpoint" \
182179
--arguments ${ADDRESS_ARGUMENT} $1 $2 ${THIRD_BIGUINT_ARGUMENT}\
183180
--send || return
@@ -194,7 +191,7 @@ myNonPayableEndpoint 10000 100000
194191
Using unencoded values (for easier reading) would translate into:
195192

196193
```shell
197-
myNonPayableEndpoint erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49swp3 10000 100000 1000000
194+
myNonPayableEndpoint addr:erd14nw9pukqyqu75gj0shm8upsegjft8l0awjefp877phfx74775dsq49swp3 10000 100000 1000000
198195
```
199196

200197
:::caution
@@ -213,20 +210,29 @@ Now let's take a look at the following example, where we want to call a payable
213210

214211
```shell
215212
myPayableEndpoint() {
216-
method_name=str:myPayableEndpoint
217-
my_token=str:$1
213+
token_identifier=$1
218214
token_amount=$2
219215
mxpy --verbose contract call ${CONTRACT_ADDRESS} \
220216
--pem=${WALLET_PEM} \
221-
--gas-limit=6000000 \
222-
--proxy=${PROXY} --chain=${CHAIN_ID} \
223-
--function="ESDTTransfer" \
224-
--arguments $my_token $token_amount $method_name\
217+
--proxy=${PROXY} \
218+
--token-transfers $token_identifier $token_amount \
219+
--function="myPayableEndpoint" \
225220
--send || return
226221
}
227222
```
228223

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.
224+
To call a **payable endpoint**, we use the `--token-transfer` flag, which requires two values:
225+
226+
1. The token identifier.
227+
2. The amount.
228+
229+
In our case, we specify in the terminal the **token identifier** and **the amount of tokens** we want to transfer.
230+
231+
:::info
232+
When specifying the amount of tokens to transfer, the value must include the token's decimal precision.
233+
234+
For example EGLD use 18 decimals. This means that if you want to transfer 1.5 EGLD, the amount value will be $1.5 \times 10^{18}$.
235+
:::
230236

231237
[comment]: # (mx-context-auto)
232238

@@ -237,102 +243,61 @@ Now let's suppose we want to call an endpoint that accepts an NFT or an SFT as p
237243
```shell
238244
###PARAMS
239245
# $1 = NFT/SFT Token Identifier,
240-
# $2 = NFT/SFT Token Nonce,
241-
# $3 = NFT/SFT Token Amount,
242-
# $4 = Destination Address,
246+
# $2 = NFT/SFT Token Amount,
243247
FIRST_BIGUINT_ARGUMENT=1000
244248
SECOND_BIGUINT_ARGUMENT=10000
245-
MY_WALLET_ADDRESS=erd1...
246249

247250
myESDTNFTPayableEndpoint() {
248-
method_name=str:myESDTNFTPayableEndpoint
249-
sft_token=str:$1
250-
sft_token_nonce=$2
251-
sft_token_amount=$3
252-
destination_address=addr:$4
253-
mxpy --verbose contract call ${MY_WALLET_ADDRESS} \
251+
sft_token_identifier=$1
252+
sft_token_amount=$2
253+
mxpy --verbose contract call ${CONTRACT_ADDRESS} \
254254
--pem=${WALLET_PEM} \
255-
--gas-limit=100000000 \
256-
--proxy=${PROXY} --chain=${CHAIN_ID} \
257-
--function="ESDTNFTTransfer" \
258-
--arguments $sft_token \
259-
$sft_token_nonce \
260-
$sft_token_amount \
261-
$destination_address \
262-
$method_name \
263-
${FIRST_BIGUINT_ARGUMENT} \
264-
${SECOND_BIGUINT_ARGUMENT} \
255+
--proxy=${PROXY} \
256+
--token-transfers $sft_token_identifier $sft_token_amount \
257+
--function="myESDTNFTPayableEndpoint" \
258+
--arguments ${FIRST_BIGUINT_ARGUMENT} ${SECOND_BIGUINT_ARGUMENT} \
265259
--send || return
266260
}
267261
```
268262

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.
274-
275263
[comment]: # (mx-context-auto)
276264

277265
### Multi-ESDT transfer
278266

279267
In case we need to call an endpoint that accepts multiple tokens (let's say for example 2 fungible tokens and an NFT). Let's take a look at the following example:
280268

281269
```shell
282-
283270
###PARAMS
284-
# $1 = Destination Address,
285-
# $2 = First Token Identifier,
286-
# $3 = First Token Amount,
287-
# $4 = Second Token Identifier,
288-
# $5 = Second Token Amount,
271+
# $1 = First Token Identifier,
272+
# $2 = First Token Amount,
273+
# $3 = Second Token Identifier,
274+
# $4 = Second Token Amount,
275+
# $5 = Third Token Identifier,
289276
# $6 = Third Token Identifier,
290-
# $7 = Third Token Nonce,
291-
# $8 = Third Token Identifier,
292277
FIRST_BIGUINT_ARGUMENT=1000
293278
SECOND_BIGUINT_ARGUMENT=10000
294279

295280
myMultiESDTNFTPayableEndpoint() {
296-
method_name=str:myMultiESDTPayableEndpoint
297-
destination_address=addr:$1
298-
number_of_tokens=3
299-
first_token=str:$2
300-
first_token_nonce=0
301-
first_token_amount=$3
302-
second_token=str:$4
303-
second_token_nonce=0
304-
second_token_amount=$5
305-
third_token=str:$6
306-
third_token_nonce=$7
307-
third_token_amount=$8
308-
309-
mxpy --verbose contract call $user_address \
281+
first_token_identifier=$1
282+
first_token_amount=$2
283+
second_token_identifier=$3
284+
second_token_amount=$4
285+
third_token_identifier=$5
286+
third_token_amount=$6
287+
288+
mxpy --verbose contract call ${CONTRACT_ADDRESS} \
310289
--pem=${WALLET_PEM} \
311-
--gas-limit=100000000 \
312-
--proxy=${PROXY} --chain=${CHAIN_ID} \
313-
--function="MultiESDTNFTTransfer" \
314-
--arguments $destination_address \
315-
$number_of_tokens \
316-
$first_token \
317-
$first_token_nonce \
318-
$first_token_amount \
319-
$second_token \
320-
$second_token_nonce \
321-
$second_token_amount \
322-
$third_token \
323-
$third_token_nonce \
324-
$third_token_amount \
325-
$method_name \
326-
${FIRST_BIGUINT_ARGUMENT} \
327-
${SECOND_BIGUINT_ARGUMENT} \
290+
--proxy=${PROXY} \
291+
--token-transfers $first_token_identifier $first_token_amount \
292+
$second_token_identifier $second_token_amount \
293+
$third_token_identifier $third_token_amount \
294+
--function="payable_nft_with_args" \
295+
--arguments ${FIRST_BIGUINT_ARGUMENT} ${SECOND_BIGUINT_ARGUMENT} \
328296
--send || return
329-
}
330297
```
331298
332299
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.
333300
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.
335-
336301
:::tip
337302
More information about ESDT Transfers [here](/tokens/fungible-tokens/#transfers).
338303
:::

0 commit comments

Comments
 (0)