Docs

Docs

  • Develop
  • Validate
  • Integrate
  • Learn

›Gas and Fees

Welcome to Elrond

  • Welcome to Elrond

Technology

  • Architecture Overview
  • Glossary
  • Entities
  • Chronology
  • Secure Proof of Stake
  • Adaptive State Sharding
  • The Elrond WASM VM
  • Cross Shard Transactions

Wallet

  • Wallets - Overview
  • Web Wallet
  • Maiar Web Wallet Extension
  • Webhooks
  • Ledger

Tokens

  • Native Tokens
  • ESDT tokens
  • NFT tokens

Validators

  • Validators - Overview
  • System Requirements
  • Install a Mainnet Node

    • Scripts & User config
    • Installing a Validator Node
    • Optional Configurations
    • How to use the Docker Image

    Install a Testnet/Devnet Node

    • Scripts & User config
    • Installing a Validator Node
    • Manage a validator node
    • How to use the Docker Image

    Manage your keys

    • Validator Keys
    • Wallet Keys
    • Protecting your keys

    Staking, Unstaking, Unjailing

    • Staking, unstaking and unjailing
    • Staking
    • Unjailing
    • The Staking Smart Contract
  • The Delegation Manager
  • Convert An Existing Validator Into A Staking Pool
  • Merging A Validator Into An Existing Delegation Smart Contract
  • Rating
  • Elrond Node upgrades
  • Node redundancy
  • Import DB
  • Node CLI
  • Node Databases
  • Useful Links & Tools
  • FAQs

Developers

  • Developers - Overview
  • Tutorials

    • Build a dApp in 15 minutes
    • Build a Microservice for your dApp
    • The Crowdfunding Smart Contract (part 1)
    • The Crowdfunding Smart Contract (part 2)
    • The Counter Smart Contract
    • Custom Wallet Connect

    Signing Transactions

    • Signing Transactions
    • Tools for signing
    • Signing programmatically

    Gas and Fees

    • Overview
    • EGLD transfers (move balance transactions)
    • System Smart Contracts
    • User-defined Smart Contracts

    Developer reference

    • The Elrond Serialization Format
    • Smart contract annotations
    • Smart contract modules
    • Smart contract to smart contract calls
    • Smart Contract Developer Best Practices
    • Code Metadata
    • Smart Contract API Functions
    • Storage Mappers
    • Rust Testing Framework
    • Rust Testing Framework Functions Reference
    • Rust Smart Contract Debugging
    • Random Numbers in Smart Contracts

    Developers Best Practices

    • Basics
    • BigUint Operations
    • The dynamic allocation problem
    • Multi-values

    Mandos tests reference

    • Mandos Overview
    • Mandos Structure
    • Mandos Simple Values
    • Mandos Complex Values
    • Embedding Mandos code in Go
  • Constants
  • Built-In Functions
  • Account storage
  • Setup a Local Testnet
  • Set up a Local Testnet (advanced)
  • Creating Wallets

SDK and Tools

  • SDKs and Tools - Overview
  • REST API

    • REST API overview
    • api.elrond.com
    • Gateway overview
    • Addresses
    • Transactions
    • Network
    • Nodes
    • Blocks
    • Virtual Machine
    • Versions and Changelog
  • Proxy
  • Elasticsearch
  • erdpy

    • erdpy
    • Installing erdpy
    • Configuring erdpy
    • erdpy CLI
    • Deriving the Wallet PEM file
    • Sending bulk transactions
    • Writing and running erdpy scripts
    • Smart contract interactions

    erdjs

    • erdjs
    • Cookbook
    • Extending erdjs
    • Writing and testing interactions
    • Migration guides
    • Signing Providers for dApps
  • erdgo
  • erdcpp
  • erdjava
  • erdkotlin
  • erdwalletjs-cli

Integrators

  • Integrators - Overview
  • EGLD integration guide
  • ESDT tokens integration guide
  • Observing Squad
  • Accounts Management
  • Creating Transactions
  • Querying the Blockchain

User-defined Smart Contracts

For user-defined Smart Contract deployments and function calls, the actual gas consumption of processing contains both of the previously mentioned cost components - though, while the value movement and data handling component is easily computable (using the previously depicted formula), the contract execution component is hard to determine precisely a priori. Therefore, for this component we have to rely on simulations and estimations.

For simulations, we will start a local testnet using erdpy (detailed setup instructions can be found here). Thus, before going further, make sure your local testnet is up and running.

Contract deployments

In order to get the required gasLimit (the actual gas cost) for a deployment transaction, one should use the well-known erdpy contract deploy command, but with the --simulate flag set.

At first, pass the maximum possible amount for gas-limit (no guessing).

$ erdpy --verbose contract deploy --bytecode=./counter.wasm \
 --recall-nonce --gas-limit=600000000 \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --simulate

In the output, look for txGasUnits. For example:

"txSimulation": {
    ...
    "cost": {
        "txGasUnits": 1849711,
        ...
    }
}
note

The simulated cost txGasUnits contains both components of the cost.

After that, check the cost simulation by running the simulation once again, but this time with the precisegas-limit:

$ erdpy --verbose contract deploy --bytecode=./counter.wasm \
 --recall-nonce --gas-limit=1849711 \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --simulate

In the output, look for the status - it should be success:

"txSimulation": {
    "execution": {
        "result": {
            "status": "success",
            ...
        },
        ...
    }

In the end, let's actually deploy the contract:

$ erdpy --verbose contract deploy --bytecode=./counter.wasm \
 --recall-nonce --gas-limit=1849711 \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --send --wait-result
important

For deployments, the execution component of the cost is associated with instantiating the Smart Contract and calling its init() function.

If the flow of init() is dependent on input arguments or it references blockchain data, then the cost will vary as well, depending on these variables. Make sure you simulate sufficient deployment scenarios and increase (decrease) the gas-limit.

Contract calls

In order to get the required gasLimit (the actual gas cost) for a contract call, one should first deploy the contract, then use the erdpy contract call command, with the --simulate flag set.

important

If the contract makes further calls to other contracts, please read the next section.

Assuming we've already deployed the contract (see above) let's get the cost for calling one of its endpoints:

$ erdpy --verbose contract call erd1qqqqqqqqqqqqqpgqygvvtlty3v7cad507v5z793duw9jjmlxd8sszs8a2y \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --function=increment\
 --recall-nonce --gas-limit=600000000\
 --simulate

In the output, look for txGasUnits. For example:

"txSimulation": {
    ...
    "cost": {
        "txGasUnits": 1225515,
        ...
    }
}

In the end, let's actually call the contract:

$ erdpy --verbose contract call erd1qqqqqqqqqqqqqpgqygvvtlty3v7cad507v5z793duw9jjmlxd8sszs8a2y \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --function=increment\
 --recall-nonce --gas-limit=1225515\
 --send --wait-result
important

If the flow of the called function is dependent on input arguments or it references blockchain data, then the cost will vary as well, depending on these variables. Make sure you simulate sufficient scenarios for the contract call and increase (decrease) the gas-limit.

Contracts calling (asynchronously) other contracts

important

Documentation in this section is preliminary and subject to change. Furthermore, only asynchronous calls are covered.

Before moving forward, make sure you first have a look over the following:

  • Asynchronous calls between contracts
  • Asynchronous calls (Rust framework)
  • Callbacks (Rust framework)

Suppose we have two contracts: A and B, where A::foo(addressOfB) asynchronously calls B::bar() (e.g. using asyncCall()).

Let's deploy the contracts A and B:

$ erdpy --verbose contract deploy --bytecode=./a.wasm \
 --recall-nonce --gas-limit=5000000 \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --send --wait-result --outfile=a.json

$ erdpy --verbose contract deploy --bytecode=./b.wasm \
 --recall-nonce --gas-limit=5000000 \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --send --wait-result --outfile=b.json

Assuming A is deployed at erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts, and B is deployed at erd1qqqqqqqqqqqqqpgqj5zftf3ef3gqm3gklcetpmxwg43rh8z2d8ss2e49aq, let's simulate A::foo(addressOfB) (at first, pass a large-enough or maximum gas-limit):

$ export hexAddressOfB=0x$(erdpy wallet bech32 --decode erd1qqqqqqqqqqqqqpgqj5zftf3ef3gqm3gklcetpmxwg43rh8z2d8ss2e49aq)

$ erdpy --verbose contract call erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --function=foo\
 --recall-nonce --gas-limit=50000000\
 --arguments ${hexAddressOfB}\
 --simulate

In the output, look for the simulated cost (as above):

"txSimulation": {
    ...
    "cost": {
        "txGasUnits": 3473900,
        ...
    }
}

The simulated cost represents the actual gas cost for invoking A::foo(), B::bar() and A::callBack().

However, the simulated cost above isn't the value we are going to use as gasLimit. If we were to do so, we would be presented the error not enough gas.

Upon reaching the call to B::bar() inside A::foo(), the Elrond VM inspects the remaining gas at runtime and temporarily locks (reserves) a portion of it, to allow for the execution of A::callBack() once the call to B::bar() returns.

With respect to the VM Gas Schedule, the aforementioned remaining gas at runtime has to satisfy the following conditions in order for the temporary gas lock reservation to succeed:

onTheSpotRemainingGas > gasToLockForCallback

gasToLockForCallback = 
    costOf(AsyncCallStep) + 
    costOf(AsyncCallbackGasLock) + 
    codeSizeOf(callingContract) * costOf(AoTPreparePerByte)
note

Subsequent asynchronous calls (asynchronous calls performed by an asynchronously-called contract) will require temporary gas locks as well.

For our example, where A has 453 bytes, the gasToLockForCallback would be (as of February 2022):

gasToLockForCallback = 100000 + 4000000 + 100 * 453 = 4145300

It follows that the value of gasLimit should be:

simulatedCost < gasLimit < simulatedCost + gasToLockForCallback

For our example, that would be:

3473900 < gasLimit < 7619200
important

As of February 2022, for contracts that call other contracts, the lowest gasLimit required by a successful execution isn't easy to determine using erdpy. While this value can be determined by a careful inspection of the local testnet logs, for the moment, the recommended approach is to start with the right-hand side of the inequality above (simulatedCost + gasToLockForCallback) and gradually decrease the value while simulating the call and looking for a successful output.

For our example, let's simulate using the following values for gasLimit: 7619200, 7000000, 6000000:

$ erdpy --verbose contract call erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --function=foo\
 --recall-nonce --gas-limit=7619200\
 --arguments ${hexAddressOfB}\
 --simulate

... inspect output (possibly testnet logs); execution is successful

erdpy --verbose contract call erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --function=foo\
 --recall-nonce --gas-limit=7000000\
 --arguments ${hexAddressOfB}\
 --simulate

... inspect output (possibly testnet logs); execution is successful

erdpy --verbose contract call erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts \
 --pem=~/elrondsdk/testwallets/latest/users/alice.pem \
 --function=foo\
 --recall-nonce --gas-limit=6000000\
 --arguments ${hexAddressOfB}\
 --simulate

... inspect output (possibly testnet logs); ERROR: out of gas when executing B::bar()

Therefore, in our case, a reasonable value for gasLimit would be 7000000.

important

In case of a highly gas-demanding callback (not recommended) which would consume more than gasToLockForCallback, one should appropriately increase the right-hand side of the gasLimit inequation depicted above, by inspecting the contract call output and the testnet logs.

← System Smart ContractsThe Elrond Serialization Format →
  • Contract deployments
  • Contract calls
  • Contracts calling (asynchronously) other contracts
Made withby the Elrond team.
GithubChat
Main siteWalletExplorerBridgeDocsGrowthMaiarMaiar Exchange