BUILD A BASIC SMART CONTRACT
In our previous article we talked about solidity, smart contract and Remix IDE, we will cover everything we’ve learnt in this session. The smart contract we want to build will help us to send funds from one wallet address to another wallet address (sender to recipient). Don’t worry, you will not have to set up another project. We will use the remix playground to do everything from writing the code, to compiling, to debugging, and finally to testing it.
Let’s now head over to https://remix.ethereum.org/ . You should have the following screen stare at you for a while:
This playground provides us with all we need to write our first smart contract.
We will now create a new file named Blockchain.sol
by clicking the document icon marked red in the image below and type the name of the file in the space provided:
.sol
is the extension used for solidity files.
Solidity code always begins with the line below:
//SPDX-License-Identifier:MIT
Without this code, you will get a warning saying “SPDX license identifier not provided in source file.” but your code will still run. It is just like saying that you accept the terms and conditions of writing Solidity.
The next thing to do is to state the Solidity version you want to use.
pragma solidity ^0.8.17;
The caret (^) sign indicates that the program will be compatible with higher versions of solidity.
Now we have to define a contract
named Blockchain
. So we have:
contract Blockchain {
}
Inside the contract above, we will create a data-type called BlockStruck
with the code below:
struct BlockStruct{
uint index;
uint amount;
uint timestamp;
address sender;
address recipient;
}
We define all the keys we expect a value for in the struct. Since solidity is a strongly typed language, we specified a data-type before each key. The struct
is similar to Object
in JavaScript.
The next thing that we want to define is an event
. An event
is usually triggered at the end of a function’s execution to send data to the frontend. You can see it like console.log,
some people also use it as a cheap way of storage.
We define a BlockEvent
that we will trigger after adding a block to the chain.
event BlockEvent(uint amount, address sender, address recipient);
Unlike struct
, circular braces are used for an event
, and their keys are separated by commas (,). Also, notice that struct
does not end with a semicolon, but event
does.
Now that we have defined the structure of blocks, let’s use it to setup an array of blocks called chain
like this:
BlockStruct[] chain;
The code above defines the chain
to be an array of BlockStruct
. As always, we specify the data-type before the variable name.
Next, define a variable to keep track of how many blocks are in the chain
:
uint chainCount;
You may choose to assign it a value on the same line (uint chainCount = 0;
) or do it in the constructor
function like this:
constructor() {
chainCount = 0;
}
The constructor
is a special function within a smart contract that is executed only once, and that happens when the contract is deployed to the blockchain.
We define a function addBlock
to add blocks to the chain
function addBlock(uint amount, address payable recipient) public {
}
Like the functions you already know, it begins with the function
keyword followed by the name of the function addBlock
and the argument it expects in braces.
One of the arguments (recipient
) has a flag called payable
, indicating that the wallet address is eligible to receive funds. Next to it is the function's visibility flag (public
).
Visibility defines who can call a function or variable. It can be public
, private
, internal
, or external
.
- A
public
function can be called by any contract. private
functions can only be called inside the contract where they are defined.- Only contracts that inherit
internal
functions can call them. external
functions are only accessible by other contracts.
In the addBlock
, we start by incrementing the chainCount
by one like this:
chainCount ++;
Next, add the block of a transaction to the chain like this:
chain.push (
BlockStruct(
chainCount,
amount,
block.timestamp,
msg.sender,
recipient
)
);
The BlockStruct
takes values corresponding to the keys set when defining the struct
. It is then added to the chain
array using the .push
method, now we have a new block in the chain
. This code adds a new block to a blockchain array by creating a block with specific data and pushing it onto the chain, effectively extending the blockchain.
Finally, we trigger the BlockEvent
we created a while ago
emit BlockEvent(amount, msg.sender, recipient);
emit
is how you trigger the BlockEvent
event, and the values inside the parentheses match the data fields you set when creating the event, so it records specific information when the event happens.
We define a function getChain
. This function takes no argument but returns a BlockStruct
.
function getChain() public view returns(BlockStruct[] memory) {
return chain;
}
The program returns the chain;
an array of all blocks.
Something to note in the function above is that we used view
to show that this function returns a value. We also indicated the kind of data type we expect to be returned (returns (BlockStruck[] memory)
) and the storage type to be used (memory
).
There are two main storage types in solidity: Storage
and Memory
.
Storage
is the default type of storage used to hold data permanently for a program while Memory
is temporary and is less expensive in terms of gas.
The getChainCount
, this function takes no argument. It returns the number of blocks added to the chain
function getChainCount() public view returns(uint) {
return chainCount;
}
That completes the smart contract that we intended to create. Now the code looks like this:
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.17;
contract Blockchain {
struct BlockStruct{
uint index;
uint amount;
uint timestamp;
address sender;
address recipient;
}
event BlockEvent(uint amount, address sender, address recipient);
BlockStruct[] chain;
uint chainCount;
constructor() {
chainCount = 0;
}
function addBlock(uint amount, address payable recipient) public {
chainCount ++;
chain.push(
BlockStruct(
chainCount,
amount,
block.timestamp,
msg.sender,
recipient
)
);
emit BlockEvent(amount, msg.sender, recipient);
}
function getChain() public view returns(BlockStruct[] memory) {
return chain;
}
function getChainCount() public view returns(uint) {
return chainCount;
}
}
How to Compile the Smart Contract
We need to compile the code to check if there are errors that we need to fix. The steps below will help us do just that:
- Click on the third icon on the left side menu of the remix IDE:
- Then click the
Compile
button:
The compilation was successful since we have no errors.
How to Deploy the Smart Contract
Now that compilation is successful, let’s deploy the contract.
- Click on the fourth icon in the side menu:
select Remix VM (London)
for the ENVIRONMENT
. It has ten (10) accounts with 100 dummy ethers each that you may use for test purposes.
- Then click the
Deploy
button. Now when you scroll to the bottom, you will find theBlockchain
contract under Deployed Contracts. - Click the arrow by the deployed contract name to see the functions of the contract that you can interact with.
There are three (3) functions in the image above that match the three (3) functions we defined in our smart contract. Remix automatically creates a UI for you to test your contracts as soon as you deploy them. We will now test the functions we created to see how they respond.
How to test the addBlockToChain function
To test the addBlockToChain
function
- Click the caret (^) icon by the side of the function button and input box. That drops down a form.
- Fill in
10
for theamount
, and fill in one of the ten 10 account addresses for therecipient
:
- Click the
transact
button.
Note that you cannot send funds to the same address you used to deploy the contract. You must choose a different account.
How to test the getChain function
Click the getChain
button to reveal the blocks in the chain so far:
It returns a tuple
, which is a kind of array
. Recall that chain
is supposed to be an array
containing a list of blocks.
How to test the getChainCount function
To get the number of blocks added, click the getChainCount
button:
And just as we defined it, it returns a uint
. There is just one item in the chain
for now, but as you keep adding more blocks, the number will increase.
Congratulations! if you made it this far, you’ve learnt how to write your own smart contract, compile and deploy it.