Get Started With Your First Smart Contract
By: Alex Roan
Tags: Blockchain, Smart Contracts, Ethereum, Bitcoin, Programming

Making Up the Rules

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.

Figure 1: MyWallet.sol

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!