Tutorial on Smart contract for Newbies

Code Your First ERC20 token                            

Smart contracts are self-executing contracts with the terms of the agreement between buyer and seller being directly written into lines of code. They are basically used to define actions performed on the blockchain.

How Smart Contracts Work

Smart contracts were first proposed in 1994 by Nick Szabo, an American computer scientist who invented a virtual currency called "Bit Gold" in 1998, fully 10 years before the invention of bitcoin. In fact, Szabo is often rumored to be the real Satoshi Nakamoto, the anonymous inventor of bitcoin, which he has denied.Enough of that, to know more about that you can check out https://www.investopedia.com/terms/s/smart-contracts.asp investopedia article to know more about it.

When it comes to writing smart contract a convenient language for both beginners and advanced developers is called Solidity. and that is what we're going to use and write our very first own smart contract which basically performs the Ethereum EIP 20 which is a standard API for token smart contract. Check out the github repo for more information on it. 

​A standard interface allows any tokens on Ethereum to be re-used by other applications: from wallets to decentralized exchanges.

Everything we're going to do will be on localhost and we'll run test to make sure our code is error free.

A test is a simple process of executing code program or application with the intent to find errors and make sure they're fit for use.

There are some neccessary things to have on our pc before we proceed. Fist is to make sure you have a Command line interface, secondly is to use the truffle library, truflle helps developers to create dapps and also it comes with flavors for other types of platform, for android, react apps and more. You can check them out using this link. Secondly download Ganachie-cli for you Operating system. You can choose to install it using the npm command, I prefer you go for a standalone version for your System.

npm install -g truffle

Ganache-Cli helps us to have demo accounts which contains ethereum with accounts have at least 100eth, which are used as gas for transactions.

A little introduction of my interest in solidity.

Back in 2017, I had this very close freind of mine, who was always fund of online business and transactions. I have always been someone who loves the web, but my attention was mainly on building websites and making things work on the web. I never knew there was anything like the coding part of this. Not until early 2021 I got informed and I was wowed as to the creation of tokens, as it may please, I got interested immediately and started learning that asap.


Create Our Smart Contract.

Let's move on to create our smart contract token.

This token will have this abilities below:
  • Check for token total supply
  • Transfer token to other accounts
  • Perform delegated transactions

Step 1:
Create a project using the command line 
 truffle init project_name
Step 2:
Create a second file 
SappToken.sol
Step 3: 
Inside the SappToken.sol file, add the solidity version 
 pragma solidity ^0.5.16;

Step 4:
create the class with the same file name
contractSappToken {    }

Step 5: Add some basic data needful for our contract.

stringpublic name = "Sam Token"
stringpublic symbol = "SAPP"
stringpublic standard = "SApp Token v1.0"
uint256public totalSupply;
​So if you notice from the above code, we added the name and symbol, standard and total supply.

Right now inside our contract, let's move on to add a method our function which will return the total supply.

    function allSupply(public view returns (uint256{
            return totalSupply;
    }
​We simply returned the total supply and we maded the function to be public and also added the return type.

Let's run a simple test to check if that works.

Step 6:
Go over to test folder and create a SappToken.js file. with the help of this test file created, we will have access to migration.
Go into the migrations folder and create 2_depoly_contract.js and add this lines to it

    const SappToken = artifacts.require("SappToken");
    module.exports = function (deployer{
    deployer.deploy(SappToken, 1000000);
    };

Now back in our test/SappToken.js file add this run test code, which we will use to test for the token supply

  const SappToken = artifacts.require("./SappToken");

 contract("SappToken", (accounts) => { 
     var tokenInstance;
      // Check for total Number of tokens
    it("should check for total supply", function()
         return SappToken.deployed() .then(function(instance)
         tokenInstance = instance; 
         return tokenInstance.allSupply(); 
 }) .then(function(supply)
         assert.equal(
            supply.toNumber(), 1000000, "total supply is wrong"); }); 
}); });

now on the command line interface run
truffle test
After that we should be able to see passed if everything worked perfectly.

What we simply did was to calll the deployed token and assigned the instance to tokenInstance and used the token instance to call the applySupply() method. We also used the assert, which was used to make sure we do have a true value or throw an error if anything goes wrong.

Step 7: 
Now lets send some token. To send tokens we need to make sure that the valute of tokens we want to send to any address has more tokens than the amount value we pass in our function from the test. So if you check the transfer function, you would see the require checker.

// Check if the admin account has more tokens than specified 
require(balanceOf[msg.sender] >= _value);

​Remove the tokens from the sender account and add it to the address receiving the account 

 balanceOf[msg.sender] -= _value; 
 balanceOf[_to] += _value;

then we now emit the Transfer event to send the token to the sender.

emit Transfer(msg.sender, _to, _value);
function transfer(address _to, uint256 _value)
        public
        returns (bool success)
    {
        // Check if the admin account has more tokens than specified
        require(balanceOf[msg.sender] >= _value);
        // Remove the tokens from the sender account and add it to the address receiving the account
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        // Tranfer Event
        emit Transfer(msg.sender, _to, _value);
        return true;
    }


​Writing the transfer test

// Transfer token
  it("used to transfer token to other accounts"function () {
    return SappToken.deployed()
      .then(function (instance) {
        tokenInstance = instance;
        return tokenInstance.totalSupply();
      })
      .then(function (totalSupply) {
        assert.equal(
          totalSupply.toNumber(),
          1000000,
          "check if total supply is 10,000,000"
        );
        return tokenInstance.balanceOf(admin);
      })
      .then(function (adminBalance) {
        assert.equal(
          adminBalance.toNumber(),
          1000000,
          "it allocates the initial supply to the admin account"
        );
        return tokenInstance.transfer(buyer, 250000, {
          from: admin,
        });
      })
      .then((receipt) => {
        assert.equal(receipt.logs.length, 1"triggers one event");
        assert.equal(receipt.logs[0].event, "Transfer""if Transfer event?");
        assert.equal(
          receipt.logs[0].args._from,
          admin,
          "main account to transfer from?"
        );
        assert.equal(
          receipt.logs[0].args._to,
          buyer,
          "same account trasnferred to?"
        );
        // Return balance of account 1
        return tokenInstance.balanceOf(accounts[1]);
      })
      .then((balance) => {
        assert.equal(
          balance.toNumber(),
          250000,
          "return the amount of account[1]"
        );
        // Return balance of the account which made the transfer
        return tokenInstance.balanceOf(admin);
      })
      .then((balance) => {
        assert.equal(
          balance.toNumber(),
          750000,
          "check if the main account balance is reduced by 250,000"
        );
      });
  });

Step 8: Delegated Transfers - Delegated transafers allows account B to have access to account A and account A will be able to make a transfer to account C. 

One thing I have not really touched is about accounts, this accounts are provided by the ganache-cli, and each account has at least 100eth.

function transferFrom(
        address _from,
        address _to,
        uint256 _value
    public returns (bool success{
        // Value is less than the amount of tokens inside Account A
        require(_value <= balanceOf[_from]);
        // Value is less than the amount of tokens Account B has access to from account a
        require(_value <= allowance[_from][msg.sender]);
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        
        // The value gets removed from both account
        allowance[_from][msg.sender] -= _value;
        // Allow account B to send token to Account C
        emit Transfer(_from, _to, _value);
        return true;
    }

​Now let's move on and write the test

it("handles delegated token transfers"function ({
        var fromAccount = accounts[2];
        var spendingAccount = accounts[3];
        var toAccount = accounts[3];
        return SappToken.deployed()
        .then((instance) => {
            tokenInstance = instance;
            tokenInstance.transfer(fromAccount, 1000, { from: admin });
            return tokenInstance.balanceOf(fromAccount);
        })
        .then((balance) => {
            return tokenInstance.approve(spendingAccount, 800, {
            from: fromAccount,
            });
        })
        .then((receipt) => {
            return tokenInstance.transferFrom(fromAccount, toAccount, 99, {
            from: spendingAccount,
            });
        })
        .then(function (receipt{
            assert.equal(receipt.logs.length, 1"triggers one event");
            assert.equal(
            receipt.logs[0].event,
            "Transfer",
            'should be the "Transfer" event'
            );
            assert.equal(
            receipt.logs[0].args._from,
            fromAccount,
            "logs the account the tokens are transferred from"
            );
            assert.equal(
            receipt.logs[0].args._to,
            toAccount,
            "logs the account the tokens are transferred to"
            );
            assert.equal(
            receipt.logs[0].args._value,
            99,
            "logs the transfer amount"
            );
            return tokenInstance.balanceOf(fromAccount);
        });
    });
   });

Right now with our little explantions above, you'll be able to write test for your smart contracts. Now this is the full source code for our SappToken.sol

 pragma solidity ^0.5.16;
    contract SappToken {
        string public name = "Sam Token";
        string public symbol = "SAPP";
        string public standard = "SApp Token v1.0";
        uint256 public totalSupply;
        // EIP's
        mapping(address => uint256) public balanceOf;
        mapping(address => mapping(address => uint256)) public allowance;
        // Events
        event Transfer(address indexed _from, address indexed _to, uint256 _value);
        event Approval(
            address indexed _owner,
            address indexed _spender,
            uint256 _value
        );
        constructor(uint256 _initialSupply) public {
            balanceOf[msg.sender] = _initialSupply;
            totalSupply = _initialSupply;
        }
        // Return the token total Supply and Return Type
        function allSupply() public view returns (uint256) {
            return totalSupply;
        }
        function transfer(address _to, uint256 _value)
            public
            returns (bool success)
        {
            // Check if the admin account has more tokens than specified
            require(balanceOf[msg.sender] >= _value);
            // Remove the tokens from the sender account and add it to the address receiving the account
            balanceOf[msg.sender] -= _value;
            balanceOf[_to] += _value;
            // Tranfer Event
            emit Transfer(msg.sender, _to, _value);
            return true;
        }
        function approve(address _spender, uint256 _value)
            public
            returns (bool success)
        {
            allowance[msg.sender][_spender] = _value;
            emit Approval(msg.sender, _spender, _value);
            return true;
        }
        function transferFrom(
            address _from,
            address _to,
            uint256 _value
        ) public returns (bool success) {
            // Value is less than the amount of tokens inside Account A
            require(_value <= balanceOf[_from]);
            // Value is less than the amount of tokens Account B has access to from account a
            require(_value <= allowance[_from][msg.sender]);
            balanceOf[_from-_value;
            balanceOf[_to] += _value;
            
            // The value gets removed from both account
            allowance[_from][msg.sender-_value;
            // Allow account B to send token to Account C
            emit Transfer(_from_to_value);
            return true;
        }
    }