Smart contracts are comprised mainly of functions so it is important to understand how to construct one and all the various options available.
From the solidity documentation, the syntax of a function is as follows:
function FunctionName([parameters]) {public|private|internal|external} [pure|constant|view|payable] [modifiers] [returns (<return types>)]
What this means is that when creating a function, here are the required steps.
- Use the function keyword
- Provide a function name
- Provide parameters if required
- Set the function’s visibility. There’s 4 options to choose from. public, private, internal, or external:
- Set the behaviour of the function. Choose from view, pure, or payable.
- Add any applicable modifiers
- Add any applicable return types/parameters
Here is a brief explanation of the different visibilities.
Public: All (contracts can a call the function)
Private: Only this contract
Internal – only this contract and contracts deriving from it
External – Cannot be accessed internally, only externally.
Private is a subset of internal and external is a subset of public. For a more detailed and intriguing analysis of the difference between public and external check this. (TLDR: public uses more gas because it uses memory instead of calldata). (Check the docs for more details).
The behaviours are defined as:
View: Can read the state but will not modify storage state in any way.
Pure: More restrictive than view and does not read or write to the storage state
Payable: Accepts incoming payments
As noted in the docs, statements that are considered modifying state include:
- Writing to state variables.
- Emitting events.
- Creating other contracts.
- Using
selfdestruct
. - Sending Ether via calls.
- Calling any function not marked
view
orpure
. - Using low-level calls.
- Using inline assembly that contains certain opcodes.
View and pure replaces the “constant” keyword and indicates to the compiler that storage data would not be written as a result of the function call. Therefore network verification is not required. This means no transaction to mine, resulting in no gas needed to be spent. These functions were essentially look-ups for data held in or derived from a contract’s state.
Pure functions are completely independent of outside state, are the simplest reusable building blocks of code in a program, and are recommended to be used. For further reading, check this out: https://www.youfoundron.com/blog/solidity-constant-vs-view-vs-pure/
Let’s ignore modifiers for now. For return type, if the function returns something this is required. Let’s look at some examples.
function getMessage() public view returns (string memory) { return message; }
Here is a simple function. Let’s use our checklist.
- Use the function keyword. YES
- Provide a function name. getMessage
- Provide parameters if required. No parameters here.
- Set the function’s visibility. Public
- Set the behaviour of the function. View
- Add any applicable modifiers. No modifiers
- Add any applicable return types/parameters. Returns 1 parameter of type string located in memory. NB: in v5.0+ data location needs to be specified.
Payable functions
A payable function is one where ether can be sent to it. This is how ether can be sent to a smart contract. Examples include:
function deposit() payable {}; function payme() payable{ amount += msg.value; }
NB: It is not possible to have payable as a function name as it is a reserved keyword.
Here is a full contract to try:
pragma solidity ^0.5.1; contract HelloWorld { string message = "Welcome"; function getMessage() public view returns (string memory) { return message; } function getBalance() public view returns (uint256){ return address(this).balance; } function acceptPayment() public payable{ } }
Fallback function
There is a special feature in a solidity smart contract where it can have precisely one unnamed function which cannot have any arguments or return anything back. This is called a fallback function. This fall back function gets executed when a contract is called and no other function matches, or if no data is supplied.
pragma solidity 0.5.1; contract fallingback { function () external { } }
Note that in v0.5 and above, fallback functions need to be defined as external. This fallback function doesn’t do anything useful. The following is more useful.
pragma solidity 0.5.1; contract fallingback { // fall back function function () external payable { } // getter function function getBalance() public payable returns (uint256) { return address(this).balance; } }
Deploy this in Remix and run the fallback function and don’t forget to include a value of say 1 ether. Then call the getBalance function.
1 thought on “Understanding basic functions in solidity”