eatthecode.com

Solidity CRUD

Introduction

This guide will explore the basics of CRUD (create, read, update and delete) operations using solidity. We will show also the event emitter that can be applied in every operation which can be used in log and in many other beneficial things. The post also will illustrate the test of the operations using the chai library.

  Solidity CRUD

Solidity CRUD

C.R.U.D

The CRUD (create, read, update and delete) operation is very obvious happening in many scenarios in the software industry. With blockchain technology and as it still does not have a long history such transactions may be a challenge. For instance, the delete operation is challenging when you write a smart contract in solidity and it is illustrated in the examples below.

Definitions

Solidity

Solidity is a programming language that is used in writing smart contracts. Solidity is similar to javascript in its syntax. Solidity is very famous in blockchain programming and in writing smart contracts. The smart contract can be written using other languages such as Vyper, Yul (previously also called JULIA or IULIA), and others.

Smart contract

The smart contract is a piece of code that runs on the blockchain network. Just smart contract deployed, it can not be edited, deleted, or hacked. The smart contract can be written using different programming languages. The big benefit of the smart contract is that will be run its conditions without the need for a middleman. The smart contract can be considered the initial way to disappear banks (It is true), banks may disappear with time with huge help from smart contracts.

// an example of a smart contract

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

contract CustomerContract {
    // The Global public variables (make getters with "public")
    address public owner = msg.sender;
    uint256 public publicNumber;

    // Private variables
    uint256 private currentNumber;
    string private message;

    // A function to change the current number by any uint256 value. The stored number and the new number
    // should not be the same, If it is, it will fail with message "Identical numbers"
    // If the person who ask to change the number is not the contract owner, require function will fails
    // With returning error message "Only the owner who can update"
    function changeNumber(uint256 number) public {
        require(currentNumber != number, "Identical numbers");
        require(msg.sender != owner, "Only the owner who can update");

        currentNumber = number;
    }

    // This is how to return the current number.
    function getCurrentNumber() public view returns (uint256) {
        return currentNumber;
    }
}

Smar contract example

The smart contract CRUD

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract CustomerBalanceContract {
    struct Customer {
        uint256 id;
        string name;
    }

    Customer[] private _customers;

    uint256 private _totalCustomersCount;

    constructor() {
        _totalCustomersCount = 0;
    }

    event AddEvent(uint256 id, string name);

    event UpdatedEvent(uint256 id, string name);

    event DeletedEvent(uint256 id);

    function add(uint256 id, string memory name)
        public
        returns (uint256 totalCustomers)
    {
        Customer memory newCustomer = Customer(id, name);
        _customers.push(newCustomer);
        _totalCustomersCount++;

        //emit add event
        emit AddEvent(id, name);
        return _totalCustomersCount;
    }

    function update(uint256 id, string memory name)
        public
        returns (bool success)
    {
        for (uint256 i = 0; i < _totalCustomersCount; i++) {
            if (compare(_customers[i].id, id)) {
                _customers[i].name = name;
                emit UpdatedEvent(id, name);
                return true;
            }
        }
        return false;
    }

    function deleteCustomer(uint256 id) public returns (bool success) {
        require(_totalCustomersCount > 0);
        require(id >= _customers.length, "Index is not exist");

        for (uint i = id; i < _customers.length - 1; i++) {
            _customers[i] = _customers[i + 1];
        }
        _customers.pop();

        return true;
    }

    function getCustomer(uint256 id) public view returns (Customer memory) {
        for (uint256 i = 0; i < _totalCustomersCount; i++) {
            if (compare(_customers[i].id, id)) {
                return _customers[i];
            }
        }
        revert("customer not found");
    }

    function compare(uint256 a, uint256 b) internal pure returns (bool) {
        return a == b;
    }

    function getTotalCustomersCount() public view returns (uint256) {
        return _totalCustomersCount;
    }

    function getTotalCustomers() public view returns (Customer[] memory) {
        return _customers;
    }
}

 

Event Emitters

Event is an inheritable member of a contract. An event is emitted, it stores the arguments passed in transaction logs. These logs are stored on the blockchain and are accessible using the address of the contract till the contract is present on the blockchain. An event generated is not accessible from within contracts, not even the one that has created and emitted them.

Testing

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("CustomerBalanceContract", function () {
  it("Should return empty array", async function () {
    const CustomerBalanceContract = await ethers.getContractFactory(
      "CustomerBalanceContract"
    );
    const customerBalanceContract = await CustomerBalanceContract.deploy();
    await customerBalanceContract.deployed();

    expect(await customerBalanceContract.getTotalCustomersCount()).to.equal(0);

    const addItemTransaction = await customerBalanceContract.add(1, "Shaban");

    // wait 1 approval
    await addItemTransaction.wait(1);

    expect(await customerBalanceContract.getTotalCustomersCount()).to.equal(1);
  });
});

 

Deploy

// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
const hre = require("hardhat");

async function main() {
  // Hardhat always runs the compile task when running scripts with its command
  // line interface.
  //
  // If this script is run directly using `node` you may want to call compile
  // manually to make sure everything is compiled
  // await hre.run('compile');

  // We get the contract to deploy
  const CustomerBalanceContract = await hre.ethers.getContractFactory(
    "CustomerBalanceContract"
  );
  const customerBalanceContract = await CustomerBalanceContract.deploy();

  await customerBalanceContract.deployed();

  console.log(
    "CustomerBalanceContract deployed to:",
    customerBalanceContract.address
  );
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

 

Run/compile at hardhat

Using hardhat, you can simply run the commands

npx hardhat compile

or

yarn hardhat compile

Any of the above commands will compile the smart contracts to the hardhat local network. If you need to run on another network such as Rinkeby or Ethereum Mainnet network, you can configure the “hardhat.config.js” file.

Conclusion

We showed the usage of solidity with hardhat to apply different CRUD (create, read, update and delete) with showing how can we run different unit tests using the javascript chai library. The post has an example of a smart contract that is written in solidity language.

You can find sample source codes on Github Enjoy…!!!

I can help you to build such as software tools/snippets, you contact me from here

 
Exit mobile version