If you’re familiar with object-oriented programming languages, think of a Solidity smart contract as a class.
Like any other language, Solidity has a range of data types including:
- Booleans
- Integers
- Strings
- Addresses
- Fixed-point numbers
- Arrays
There are access modifiers that define who and what can access variables and functions:
- Public
- Private
- Internal
- External
A smart contract can have state and local variables, a constructor, and functions.
Crucially, Solidity allows any contract to access Blockchain information (like how much ETH a particular address has) using globally available variables. These are vital to performing safe rule-based operations like sending ETH to other addresses.
So, if a smart contract is a wallet with rules, let’s use that as an example. Let’s make a simple wallet contract that can hold, send, and receive ETH.
Let’s go from top to bottom, then check that we meet all the criteria that we set out for our wallet.
Define Solidity version
Define the solidity compiler version with pragma solidity …
. We’re using 0.6.0
here.
Define contract name
contract MyWallet {
Owner state variable
We need to keep track of who owns this wallet. This is stored in a state variable called owner
, which we define inside the contract but outside of any function. This means all functions have access to the value stored in this variable.
It has private
visibility, meaning only functions in this contract can access it. And it stores address payable
type data. payable
means that this contract can send Ether to it.
The constructor
constructor()
is executed when the contract is created on the blockchain. The only line inside this function is to store the address of the deployer. We already know that every smart contract has an address, but they must be deployed using an existing address.
This is where we see the first usage of a globally available variable. msg.sender
represents the address of the deployer (the person/wallet/smart contract that executed this function).
Any address can deploy a smart contract or call any function in a smart contract, whether it’s a human-controlled wallet or another smart contract.
At this point, there are two addresses in play: the deployer address (msg.sender
) and the address to which this contract has been deployed (more on this as we work our way through the code).
Receive Ether
For this contract to be able to receive ETH from addresses sending to it, it needs a receive()
function. This is a special function defined in Solidity that any contract wishing to receive ETH must implement. It must have the access modifier external
so outside addresses can reach it, and it must be payable
, meaning it can receive ETH (much like our owner can receive ETH and is therefore payable also).
Send Ether
The last function is called sendEther()
. This is what facilitates the owner sending ETH from this wallet contract to another address. It takes two parameters: the address to send the ETH to and the amount to send.
Notice there are two require
statements at the beginning of this function. These ensure that certain criteria are true before the function can proceed. If any requirements fail, the transaction is completely reverted.
The first requirement:
require(msg.sender == owner, "...");
This ensures that the address that called this function is the owner of the wallet. We don’t want anyone who isn’t the owner being able to send ETH to someone. Only the owner should be able to do that.
The second requirement:
require(address(this).balance >= _amount, "...");
This ensures that the wallet contract has enough ETH to send. It can’t transfer more than it owns.
This is another example of using globally accessible variables to query the amount of ETH this contract has. address(this)
gets the address that this smart contract is deployed to, then .balance
returns the amount of ETH the address has. As long as it’s greater than or equal to the amount the function wants to send (_amount
), then we can continue!
Finally, the function sends the ETH to the target address using _to.transfer(_amount);
.