Writing your first Solidity Smart Contract with Remix IDE

Kendrick
Bina Nusantara IT Division
8 min readJun 30, 2022
Photo by Nenad Novaković on Unsplash

Solidity is an object-oriented programming language designed to target the Ethereum Virtual Machine (EVM). In this tutorial, we will create a simple Smart Contract that allows the user to deposit and withdraw Ethers from the Contract.

Remix IDE

Remix IDE is an open-source Integrated Development Environment (IDE) for Solidity. Remix IDE is available as a web app. Therefore, allowing us to write, compile, test, and deploy our Smart Contract directly on the Internet Browser. Remix Online IDE can be accessed here.

Remix Online IDE
Initial Workspace

When accessed for the first time, the IDE will pre-generate files and directories. For now, let’s just ignore the generated file and create our first Solidity file.

Right-click the “contracts” directory and click on “New File”. Then, we will enter our filename. For this tutorial, I’ll use “SimpleBank.sol”.

First things first, In Solidity we need to declare the language version to be used for the compiler. This can be done by using the pragma keyword.

pragma solidity 0.9.0;

This line of code tells the compiler to use solidity version 0.9.0. We can also input a range of versions to be used.

pragma solidity >=0.7.0 <0.9.0;

This will tell the compiler to use version 0.7.0 as the minimum and 0.9.0 as the maximum.

Writing the Smart Contract

Defining a contract in Solidity is similar to defining a class in other programming languages. To define a contract we can use the contract keyword followed by the name of our contract.

Let’s add variables inside our contract. Solidity’s Data Types can be found here. For now, let’s just use an unsigned integer (uint) to store the total balance of Ethers in the Smart Contract. To declare a variable in Solidity, we first write the data type and then the variable name. Optionally, we can add an access modifier such as private and public before the variable name.

Let’s create a constructor to initialize the totalBalance variable to 0. We can do this by assigning totalBalance = 0 inside the constructor.

Function

Now let’s create a function. The following is the structure of functions in solidity

function <<functionName>>(<<parametersName>> <<parameterType>>) <<functionType>> returns(<<returnType>>) {}

Function’s visibility types:

  • public: can be called by anyone
  • private: can only be called by functions inside the contract
  • external: can be called by anyone except functions inside the contract
  • internal: can only be called by functions inside the contract and its subclass

Function’s access types :

  • view: the function only reads from the blockchain
  • pure: the function does not reads or write to the blockchain
  • payable: the function accepts payment when its called

We are creating a “getTotalBalance” function with external and view as the function type and uint as the return type. This function will return totalBalance.

Mapping

Now, we want to create a variable that can store the deposited amount by address. This can be done by using mapping. Mapping is similar to an associative array. Mapping associates a value to key. We can store and receive values by accessing the variable with the key. Mapping is declared with the following syntax

mapping(<<keyType>> => valueType>>) <<accessModifier>> <<variableName>>;

To create a variable that can store the deposited amount by address. we are mapping an address to an unsigned integer.

Let’s create another function to retrieve the balance by address.

The function will access the balanceByAddress mapping by using the message sender’s address (msg.sender) as the key.

Compiling and Running the Smart Contract

To compile the smart contract, we can click the Solidity Icon to display the Solidity Compiler Tab. In this tab, we can specify the compiler version to be used. Then, we can click on compile button to compile the code. The shortcut for compiling is Ctrl + S.

Then we can click on the Ethereum logo to view the Deploy and Run Transactions Tab. In this tab, we can choose the environment where our smart contract will be deployed, Use the generated accounts which contain test Ethers, Set the gas limit for transactions, Set the amount of ether to be transferred for the transaction, Set the contract to be used, and Deploy the Smart Contract.

We will set our Environment to Javascript VM to run a blockchain locally on our browser, select the account address for the contract deployer and then click the Deploy button.

After the contract is deployed. We can interact with the contract in the Deployed Contracts Section.

Here, we can call our smart contract’s functions by clicking on the button with the function name.

Let’s change the initialize the totalBalance variable to 10 in the constructor. When we clicked the getTotalBalance and totalBalance, the outputs are still 0. This is because we are still interacting with the unchanged contract.

Remove the current contract from the list of deployed contracts. Then, compile and deploy the modified contracts.

The modified contract is now deployed and we can interact with it.

Transactions

Now let’s create a deposit function where the user can deposit Ethers

We use the payable access type to define that the function accepts Ethers. Transfer the ether to the smart contract. Then increment balanceByAddress for the address and totalBalance.

Let’s test our deposit function. Compile and Deploy the Contract again. Then, choose another account to interact with the deposit function.

Previously, we used the first account on the list as the contract deployer. Let’s use the second account to interact with the deposit function.

We can input the amount to be paid when calling the payable function by modifying the value field. Let’s deposit 50 Ethers to the contract.

Interact with the deposit function. Looks like nothing happened. But if you check the accounts tab, we can see that our Ethers balance is decreased. Interact with the getTotalBalance function and we can see that the totalBalance is increased.

Let’s choose another account and deposit 50 Ethers again.

As we can see the getTotalBalance is increased to 100 Ethers and the getBalanceByAddress returns the total deposited amount for the current address which is 50 Ethers.

Note: Ether have 18 decimals. 1 Ether in wei represents 10¹⁸ wei. Wei is the smallest unit.

Now, Let’s create the withdraw function. In this function, we will get the amount of deposit by the address, validate if the input amount is lesser than or equal to the amount of deposit, and then transfer the number of deposited Ethers back.

First we retrieve the current balances and then use the require() function to validate if the amounts are less than or equal to the deposited amount.

The require function usage is as follows

require(<<condition>>, <<error message>>);

If the condition passed is false then the transaction will be reverted, and the error message will be returned.

Then we will wrap the withdrawal address with payable access types

address payable withdrawalAddress = payable(msg.sender);

Transfer the amount of Ether to the withdrawal address. We use the transfer method on the payable address and the amount as parameter.

withdrawAddress.transfer(amount);

Finally, deduct the deposited amount from totalBalance and balanceByAddress.

Now let’s test the withdrawal function. You can refresh the browser tab to refresh the accounts and ethers in the Deploy and Run Transactions Tab.

Compile and Deploy the contract again. Deposit 50 Ethers from Account 2 and Account 3.

And then withdraw 20 Ethers from Account 3.

Check the account tab, and interact with the getBalanceByAddress and getTotalBalance function.

As we can see, Account 3 got 20 Ethers back.

Let’s try to withdraw 50 Ethers on Account 3.

The transaction will be reverted because the condition in the require() function is not met. The error message is also displayed.

Congrats you have successfully created your first Smart Contract. The final result of the smart contract can be found here.

--

--