paint-brush
How to Code a Fantastic Batch Payment Function With Solidity: A Must Know Techniqueby@daltonic
3,209 reads
3,209 reads

How to Code a Fantastic Batch Payment Function With Solidity: A Must Know Technique

by Darlington Gospel May 4th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Solidity is a programming language for handling payment processing between accounts. This is a rare trait among the programming languages on the web. Solidity was built with the intent of managing transactions with the. Ethereum digital currency eliminating the need for middlemen and big corporations. With Solidity smart contract programming, you don’t need a bank or any bank lady to process your payment, all your payments will be processed in the network. You must understand how to process batch payments with your smart contracts.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coins Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How to Code a Fantastic Batch Payment Function With Solidity: A Must Know Technique
Darlington Gospel  HackerNoon profile picture

Introduction

Are you thinking about becoming a successful blockchain developer? Then this tutorial is for you.


The global demand for blockchain developers is out of the roof right now. Tech companies and startups are searching for blockchain developers who can help them build amazing technologies around this space.


But one of the essential skills you will need to land these high-paying jobs is to learn solidity and smart contract payment processing.


By the way, if you are looking for a personal tutor to speed you up with web3 development please book a session with me.


If you are fired up like I am, let’s jump into this tutorial…

Why you must master batch payment processing in Solidity

Solidity is a specific programming language for handling payment processing between accounts. This is a rare trait among the programming languages on the web. Solidity was built with the intent of managing transactions with the Ethereum digital currency eliminating the need for middlemen and big corporations.


With Solidity smart contract programming, you don’t need a bank or any bank lady to process your payment, all your payments will be processed in the network.


But the mere fact that solidity gives you the power to make digital transactions faster, secured, and at a large scale does not mean that you can do this perfectly without learning.


In as much that this financial network has provided us with a way to move money between points fast, secured, and limitless, It has also attracted the predatory eyes of thieves known as (hackers).


Yes, they watch out for weakness in your system specifically how money is moved in your smart contract. When they find a way to exploit such weakness, they will plunder your system and render your business dysfunctional.


For that not to happen, you must understand how to process batch payments with your smart contracts.

Batch Payment Smart Contract Example

I want to illustrate this to you through an example smart contract I’ve created named Payroll. Below is the full smart contract code…


//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

contract Payroll {
    address public companyAcc;
    uint256 public companyBal;
    uint256 public totalWorkers = 0;
    uint256 public totalSalary = 0;
    uint256 public totalPayment = 0;

    mapping(address => bool) isWorker;

    event Paid(
        uint256 id,
        address from,
        uint256 totalSalary,
        uint256 timestamp
    );

    struct PaymentStruct {
        uint256 id;
        address worker;
        uint256 salary;
        uint256 timestamp;
    }

    PaymentStruct[] employees;

    modifier ownerOnly(){
        require(msg.sender == companyAcc, "Owner reserved only");
        _;
    }

    constructor() {
        companyAcc = msg.sender;
    }

    function addWorker(
        address worker,
        uint256 salary
    ) external ownerOnly returns (bool) {
        require(salary > 0 ether, "Salary cannot be zero!");
        require(!isWorker[worker], "Record already existing!");

        totalWorkers++;
        totalSalary += salary;
        isWorker[worker] = true;

        employees.push(
            PaymentStruct(
                totalWorkers,
                worker,
                salary,
                block.timestamp
            )
        );
        
        return true;
    }

    function payWorkers() payable external ownerOnly returns (bool) {
        require(msg.value >= totalSalary, "Ethers too small");
        require(totalSalary <= companyBal, "Insufficient balance");

        for(uint i = 0; i < employees.length; i++) {
            payTo(employees[i].worker, employees[i].salary);
        }

        totalPayment++;
        companyBal -= msg.value;

        emit Paid(
            totalPayment,
            companyAcc,
            totalSalary,
            block.timestamp
        );

        return true;
    }

    function fundCompanyAcc() payable external returns (bool) {
        require(companyAcc != msg.sender, "You can't fund yourself!");
        payTo(companyAcc, msg.value);
        companyBal += msg.value;
        return true;
    }

    function getWorkers() external view returns (PaymentStruct[] memory) {
        return employees;
    }

    function payTo(
        address to, 
        uint256 amount
    ) internal returns (bool) {
        (bool success,) = payable(to).call{value: amount}("");
        require(success, "Payment failed");
        return true;
    }
}


Great, above is a smart contract for paying a company’s employees according to their salaries. Let’s take a look at how we accomplish this smart contract step by step.


Step 1: In this first step, we are setting up our smart contract structure. We are using the MIT license identifier and the compiler range of 0.7.0 to 0.9.0. Next, we defined the smart contract with a name called Payroll.


//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
contract Payroll {
  // Codes goes here...
}


Step 2: Here we are defining the essential state variables for our smart contract. The companyAcc specifies the deployment account or address. CompanyBal holds all the fund that comes into the company. We then specified some variables to keep track of the total workers, salaries, and payments in our smart contract.


address public companyAcc; // Owner's account
uint256 public companyBal; // Companies fund
uint256 public totalWorkers = 0;
uint256 public totalSalary = 0;
uint256 public totalPayment = 0;
mapping(address => bool) isWorker; // Identifies workers


Step 3: This step specifies the smart contract event log. We want some vital data logged out on each successful payout. The data to be logged out here include the payout Id, the payer, the total salary paid, and the time of payment.


event Paid(
    uint256 id,
    address from,
    uint256 totalSalary,
    uint256 timestamp
);


Step 4: This specifies the payment structure. Struct is a solidity keyword denoting structure. We want each employee to have the following records:


  • Id which must be an unsigned integer.
  • A wallet address indicated as worker.
  • A specified salary.
  • A timestamp representing the time of joining the company.


struct PaymentStruct {
  uint256 id;
  address worker;
  uint256 salary;
  uint256 timestamp;
}
PaymentStruct[] employees; //An array of employees


Step 5: In this step, we created a modifier called ownerOnly. Its sole purpose is to guard a function against unauthorized access. Whichever function we include this modifier into will only permit access to the owner of the company which in this case is the deployer of the smart contract.


modifier ownerOnly(){
    require(msg.sender == companyAcc, "Owner reserved only");
    _;
}


Step 6: Here we set up the deployer address to be the company’s account.

constructor() {
    companyAcc = msg.sender;
}


Step 7: This function is responsible for adding a new worker to the employee records. It can only be operated by the deployer of the smart contract which is the company’s account.


function addWorker(
    address worker,
    uint256 salary
) external ownerOnly returns (bool) {
    // Checks for salary and work's existence...
    require(salary > 0 ether, "Salary cannot be zero!");
    require(!isWorker[worker], "Record already existing!");
    
    // Performs essential computations...
    totalWorkers++;
    totalSalary += salary;
    isWorker[worker] = true;

    // Includes worker in the employees array...
    employees.push(
        PaymentStruct(
            totalWorkers,
            worker,
            salary,
            block.timestamp
        )
    );
    
    return true;
}


Step 8: This function is responsible for paying the company’s workers. This is the function performing the bulk transactions. You should pay good attention to it.


function payWorkers() payable external ownerOnly returns (bool) {
    // Ensures that salary can be paid...
    require(msg.value >= totalSalary, "Ethers too small");
    require(totalSalary <= companyBal, "Insufficient balance");
  
    // Performs recursive payment to each employee...
    for(uint i = 0; i < employees.length; i++) {
        payTo(employees[i].worker, employees[i].salary);
    }
    
    // Performs essential computations...
    totalPayment++;
    companyBal -= msg.value;
  
    // Emits payment event...
    emit Paid(
        totalPayment,
        companyAcc,
        totalSalary,
        block.timestamp
    );

    return true;
}


The secret to processing batch payment is to put it in a loop construct and have the loop call the secured payment function over and over again until all cases are worked on.


Step 9: This function receives payments from the outside and funds the company’s account.


function fundCompanyAcc() payable external returns (bool) {
    require(companyAcc != msg.sender, "You can't fund yourself!");
    payTo(companyAcc, msg.value);
    companyBal += msg.value;
    return true;
}


Step 10: This function simply returns the list of employees now part of the company.


function getWorkers() external view returns (PaymentStruct[] memory) {
    return employees;
}


Step 10: This function is responsible for sending money from one address to another. It was repetitively called during the batch payment to the workers.


function payTo(
    address to, 
    uint256 amount
) internal returns (bool) {
    (bool success,) = payable(to).call{value: amount}("");
    require(success, "Payment failed");
    return true;
}

Caution about Batch Payment Processing

Please note that batch payment processing is an autonomous activity put into action, hence, it is wise to do some checking before processing. Here are some tips to take note of.


Verify Data Make sure that you verify the correctness of data before processing payments. Using the required functions and special modifiers such as adminOnly to ensure that only accurate records are input into the system.


Process Payment Make sure you charge the account first before changing the state variables. This will help guard against reentrancy attacks.


Recalibrate Record Update the state variables only after you’ve done the above activities. For example, if a malicious user intends on attacking your payment function by sending multiple requests at a time. He will be compelled to pay twice, and with each request, payment has to be made before the state variables are updated.

Conclusion

Payment processing is a must-have skill if you are serious about being a web3 developer. It’s also important to know how to be defensive against attacks such as reentrancy.


That’s all for this tutorial, hope this information was valuable to you. I’m still doing private tutoring classes for those who want to jump into the web3 space. If you’re interested, please book me up on my website.


Hoping to see you in the next one, till then, have a great day!

About the Author

Gospel Darlington kick-started his journey as a software engineer in 2016. Over the years, he has grown full-blown skills in JavaScript stacks such as React, ReactNative, NextJs, and now blockchain.


He is currently freelancing, building apps for clients, and writing technical tutorials teaching others how to do what he does.


Gospel Darlington is open and available to hear from you. You can reach him on LinkedIn, Facebook, Github, or on his website.