Black friday

Save big!

All courses under $5 - for a limited time!

Code has been added to clipboard!

Local and State Solidity Variables and Use of Parameters

Reading time 7 min
Published Jul 2, 2019
Updated Sep 30, 2019

Like almost every programming language, Solidity has variables: local and state. Additionally, Solidity functions accept parameters the same as JavaScript. This tutorial discusses both variables and parameters which are defined similarly.

It also talks about the Solidity ABI which is the Contract Application Binary Interface designed for managing smart contracts. Additionally, we answer the question: how many parameters Solidity event can have?

Solidity Variables: Main Tips

  • There are two types of Solidity variables: local and state. State variables can be set as constant.
  • You can adjust variable visibility to control who can use its values.
  • Solidity handles parameters similarly to JavaScript.
  • Events accept a limited number of arguments.

Local Variables

Local variables are defined inside functions. They are kept in the stack location.

Between different function calls, the local variables do not save their value. Therefore, blockchain does not hold such values and they disappear after functions conclude.

State Variables

You declare state variables in the contract part. State variables are stored in storage. The Solidity storage keyword indicates one of the possible storing locations.

Example
pragma solidity >=0.4.0 <0.7.0;

contract SimpleStorage {
    uint storedData; // State variable
    // ...
}

Note: the word state specifies that variables indicate the state of smart contracts.

Constant State Variables

It is possible to declare state variables with Solidity constant. This assignment takes place during the compiling process since it must be set from a constant expression.

Solidity does not permit expressions that reach storage, execution or blockchain data, or makes calls to external contracts.

Note: currently, constants are used for strings and value types.

Example
pragma solidity >=0.4.0 <0.7.0;

contract C {
    uint constant x = 32**22 + 8;
    string constant text = "abc";
    bytes32 constant myHash = keccak256("abc");
}

State Variables in Storage: Layout

Solidity places variables that are statically-sized in storage from position 0 (except mapping and dynamically-sized array). It puts items that require less than 32 bytes into a single storage slot (if achievable).

Control Variable Visibility

Visibility modifiers restrict who can use values of Solidity variables. Here is a list of modifiers that change these permissions:

  • public: anyone can get the value of a variable.
  • external: only external functions can get the value of a local variable. It is not used on state variables.
  • internal: only functions in this contract and related contracts can get values.
  • private: access limited to functions from this contract.

Units and Globally Available Variables

Ether Units

Ether units indicate currency and can be used on Solidity variables or on any literal number. Literal numbers contain the following suffixes to indicate a subdenomination of Ether:

  • wei
  • finney
  • szabo
  • ether
Example
assert(1 wei == 1);
assert(1 szabo == 1e12);
assert(1 finney == 1e15);
assert(1 ether == 1e18);

Remember: specify the selected unit at the end of any literal number and the denominations will take place automatically.

Time Units

Apply the Solidity time units to any literal number to specify the selected unit of time. The following suffixes can be attached:

  • seconds
  • minutes
  • hours
  • days
  • weeks

Note: Solidity deprecated the year unit due to the issue with leap years. A similar problem exists with leap seconds (not all days have 24 hours). Be careful when using these units for calendar management.

This example shows the way days suffix affects functions:

Example
function f(uint start, uint daysAfter) public {
    if (now >= start + daysAfter * 1 days) {
      // ...
    }
}

Note: do not apply these Solidity time units to variables.

Special Functions and Variables

Variables and methods that remain permanently in the global namespace are special. They give details about the blockchain or the overall use of utility functions.

Block and Transaction Properties

Property Description
blockhash(uint blockNumber) returns (bytes32) Hash of the provided block. It functions for 256 most recent blocks (not including the current ones).
block.coinbase (address payable) Address of the current block miner.
block.difficulty (uint) Difficulty of the current block.
block.gaslimit (uint) Gas limit of the current block.
block.number (uint) Number of the current block.
block.timestamp (uint) Timestamp of the current block (in seconds since Unix epoch).
gasleft() returns (uint256) Remaining gas.
msg.data (bytes calldata) Full calldata.
msg.sender (address payable) Sender of the message.
msg.sig (bytes4) First four bytes of the calldata.
msg.value (uint) Number of wei transferred with the message.
now (uint) Timestamp of the current block.
tx.gasprice (uint) Gas price of the transaction.
tx.origin (address payable) Sender of the transaction.

External function calls can change the values of msg members (also msg.sender and msg.value).

Note: prior to Solidity version 0.4.22, blockhash was known as block.blockhash. The latter one was removed in 0.5.0 version. Additionally, gasleft was called msg.gas.

Solidity ABI Encoding and Decoding Functions

Function Description
abi.decode(bytes memory encodedData, (...)) returns (...) ABI-decodes the provided data. The second argument indicates the types.
abi.encode(...) returns (bytes memory) ABI-encodes the provided arguments.
abi.encodePacked(...) returns (bytes memory) Starts packed encoding for the provided arguments.
abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory) ABI-encodes the provided arguments (starting from the second) and adds the indicated four-byte selector.
abi.encodeWithSignature(string memory signature, ...) returns (bytes memory) Same as abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)`

Note: these methods create data for external function calls. By using them, it is possible to avoid invoking the external function.

Functions for Error Handling

Function Description
assert(bool condition) If the condition is not met, it will cause an invalid opcode and thus state change reversion (for internal errors).
require(bool condition) If the condition is not met, it will revert (for errors in inputs or external components).
require(bool condition, string memory message) If the condition is not met, it will revert (for errors in inputs or external components). Shows an error message as well.
revert() Cancels execution and reverts state changes.
revert(string memory reason) Cancels execution and reverts state changes. Gives an explanatory string.

Introduction to Parameters

Currently, Solidity default parameters do not exist. This section reviews function parameters, return variables and event parameters.

Function Parameters

Just like in JavaScript, functions accept parameters as input. As output, Solidity functions can deliver an arbitrary number of values.

Note: Solidity defines parameters and variables in the same manner. It is possible to omit unapplied parameters as well.

To make Solidity accept one type of external call with two integers, use this code:

Example
pragma solidity >=0.4.16 <0.7.0;

contract Simple {
    uint sum;
    function taker(uint _a, uint _b) public {
        sum = _a + _b;
    }
}

Return Variables

Solidity defines the return variables by following the same syntax after the keyword returns. This example shows that two results will be returned (the sum and the product of two integers included as function parameters:

Example
pragma solidity >=0.4.16 <0.7.0;

contract Simple {
    function arithmetic(uint _a, uint _b)
        public
        pure
        returns (uint o_sum, uint o_product)
    {
        o_sum = _a + _b;
        o_product = _a * _b;
    }
}

You can omit names of return variables. Use return variables as regular local variables. They have their default value (if not specified otherwise).

It is possible to explicitly assign to return variables and then leave the function using return. Also, use return statement to specify return values (single or multiple):

Example
pragma solidity >=0.4.16 <0.7.0;

contract Simple {
    function arithmetic(uint _a, uint _b)
        public
        pure
        returns (uint o_sum, uint o_product)
    {
        return (_a + _b, _a * _b);
    }
}

Event Parameters

A common question is how many parameters Solidity event can have. Event declaration is the same as function declaration. The usage of non-indexed parameters is less strict: the limit for such event arguments is 17.

Remember: arrays as arguments count as 2.

Warning: events can have up to 3 indexed arguments.

Removing Unnecessary Variable Bits

Solidity allows omitting the remaining bits of values that do not reach the length of 256-bit. The Solidity compiler removes such unnecessary bits automatically to prevent a negative effect on operations.

Note: there are some exceptions. It is not necessary to remove bits that won’t affect the next operation. For instance, boolean values should not be omitted before they are applied as a condition for JUMPI.

Solidity Variables: Summary

  • Solidity variables can either be local or state (they can also be constant).
  • You can control the visibility of variable values with modifiers.
  • Functions accept parameters, just like in JavaScript.
  • There are limitations for event parameters: up to 3 indexed parameters and 17 non-indexed ones.