Open In App

Med Chain – Solidity Project to Solve illegal Supply of Drugs

This article focuses on solving one of the major issues in society regarding the illegal supply and counterfeiting of drugs in the market. This project was created using Ethereum smart contracts to reduce the supply of drugs illegally. This project tracks the cycle of medicine from raw materials used to the hands of consumers. Every step of the medicine cycle the status of the medicine is tracked. Let’s discuss the project in detail with all the source code.

Problem Statement: To solve the issues regarding the illegal supply & counterfeiting of drugs in the market.



Use cases:

Features:



Roles & Smart Contracts

Admin:

Below is the solidity code for the above user role:




// Solidity program to implement
// the above approach
pragma solidity >=0.5.0 <0.8.6;
 
contract Admin
{
     address public owner;
 
    constructor() public
    {
        owner = msg.sender;
    }
 
    modifier onlyOwner()
    {
        require(msg.sender == owner,
                "sorry!, Only owner is allowed to visit!");
        _;
    }
 
    enum roles
    {
        norole,
        supplier,
        transporter,
        manufacturer,
        distributor,
        retailer,
        revoke
    }
     
    // Events are triggered at every step of way.
    event UserRegister(address indexed EthAddress,
                       string Name);
    event UserRoleRevoked(address indexed EthAddress,
                          string Name, uint Role);
    event UserRoleRessign(address indexed EthAddress,
                          string Name, uint Role);
 
     struct UserInfo
     {
        string name;
        string location;
        address ethAddress;
        roles role;
    }
 
      mapping(address => UserInfo) public UsersDetails;
      address[] users;
 
    function registerUser(
      address EthAddress,
      string memory Name,
      string memory Location,
      uint Role)
      public onlyOwner
      {
        require(UsersDetails[EthAddress].role ==
                roles.norole,
                "User Already registered");
        UsersDetails[EthAddress].name = Name;
        UsersDetails[EthAddress].location = Location;
        UsersDetails[EthAddress].ethAddress = EthAddress;
        UsersDetails[EthAddress].role = roles(Role);
        users.push(EthAddress);
        emit UserRegister(EthAddress, Name);
    }
 
    function revokeRole(address userAddress)
      public onlyOwner
      {
        require(UsersDetails[userAddress].role !=
                roles.norole,
                "user not registered");
        emit UserRoleRevoked(userAddress,
                             UsersDetails[userAddress].name,
                             uint(UsersDetails[userAddress].role));
        UsersDetails[userAddress].role = roles(6);
    }
 
    function reassignRole(address userAddress,
                          uint Role)
      public onlyOwner
      {
          require(UsersDetails[userAddress].role !=
                  roles.norole,
                  "User not registered");
        UsersDetails[userAddress].role = roles(Role);
        emit UserRoleRessign(userAddress,
                             UsersDetails[userAddress].name,
                             uint(UsersDetails[userAddress].role));
    }
 
    /***User Section***/
 
   function getUserInfo(address userAddress) public view returns(string memory,
                                              string memory,
                                              address, uint)
   {
       return (
           UsersDetails[userAddress].name,
           UsersDetails[userAddress].location,
           UsersDetails[userAddress].ethAddress,
           uint(UsersDetails[userAddress].role)
       );
   }
 
   function getUsersCount() public view returns(uint count)
   {
       return users.length;
   }
 
   function getUserByIndex(uint index)
     public view returns(string memory,
                         string memory,
                         address,uint)
   {
       return getUserInfo(users[index]);
   }
 
   function getRole(address _address) public view returns(uint)
   {
       return uint(UsersDetails[_address].role);
   }
 
}

Supplier

Below is the solidity program to implement the above user role:




// Solidity program to implement
// the above approach
pragma solidity >=0.5.0 <0.8.6;
import "./Admin.sol";
import "./RawMaterial.sol";
contract Supplier
{
    address admin;
    constructor(address _admin) public
    {
        admin=_admin;
    }
      enum roles
      {
        norole,
        supplier,
        transporter,
        manufacturer,
        distributor,
        retailer,
        revoke
    }
 
    mapping(address => address[]) supplierRawProductInfo;
 
    event RawSupplyInit(
        address indexed productId,
        address indexed supplier,
        address shipper,
        address indexed receiver
    );
 
    function createRawPackage(
        string memory _description,
        string memory _ownerName,
        string memory _location,
        uint256 _quantity,
        address _shipper,
        address _manufacturer
    ) public
    {
        require(roles(Admin(admin).getRole(msg.sender)) ==
                roles.supplier,
                "Only supplier can create a package!");
 
        RawMaterial rawData = new RawMaterial(
            msg.sender,
            _description,
            _ownerName,
            _location,
            _quantity,
            _shipper,
            _manufacturer
        );
 
        supplierRawProductInfo[msg.sender].push(address(rawData));
        emit RawSupplyInit(address(rawData), msg.sender,
                           _shipper, _manufacturer);
    }
          
    function getPackageCountSupplier(address _supplier) public view returns(uint)
    {
        require(roles(Admin(admin).getRole(_supplier)) ==
                roles.supplier,
                "Only supplier can get a package!");
        return supplierRawProductInfo[_supplier].length;
    }
 
    function getPackageIdByIndexSupplier(uint index,
                                         address _supplier) public view returns(address)
    {
        require(roles(Admin(admin).getRole(_supplier)) ==
                roles.supplier,
                "Only supplier can call this function!");
        return supplierRawProductInfo[_supplier][index];
    }
}

Manufacturer

Below is the solidity program to implement the above user role:




// Solidity program to implement
// the above approach
mapping(address => address[]) RawPackagesAtManufacturer;
    mapping(address => string) Hash;
    mapping(address => address[]) ManufacturedMedicine;
 
     event MedicineNewBatch(
        address indexed BatchId,
        address indexed Manufacturer,
        address shipper,
        address indexed Receiver
    );
 
    function rawPackageReceived(address rawmaterialAddress) public
    {
        require(roles(Admin(admin).getRole(msg.sender)) ==
                roles.manufacturer,
                "Only manufacturer can receive the packages");
        RawMaterial(rawmaterialAddress).receivePackage(msg.sender);
        RawPackagesAtManufacturer[msg.sender].push(rawmaterialAddress);
    }
 
    function getPackagesCountManufacturer(address _manufacturer)
      public view returns(uint)
    {
        require(roles(Admin(admin).getRole(_manufacturer)) ==
                roles.manufacturer,
                "Only Manufacturer is allowed to call this");
        return RawPackagesAtManufacturer[_manufacturer].length;
    }
 
    function getPackageIdByIndexManufacturer(uint index,
                                             address _manufacturer)
      public view returns(address)
    {
        require(roles(Admin(admin).getRole(_manufacturer)) ==
                roles.manufacturer,
                "Only Manufacturer is allowed to call this");
        return RawPackagesAtManufacturer[_manufacturer][index];
    }
 
    function manufactureMedicine(
        string memory _description,
        address _rawmaterial,
        uint _quantity,
        address _shipper,
        address _distributor
        ) public
    {
        require(roles(Admin(admin).getRole(msg.sender)) ==
                roles.manufacturer,
        "Only Manufacturer is allowed to call this");
           Medicine newMedicine = new Medicine(
                msg.sender,
                 _description,
                _rawmaterial,
                _quantity,
                _shipper,
                 _distributor
           );
           ManufacturedMedicine[msg.sender].push(address(newMedicine));
           emit MedicineNewBatch(address(newMedicine),
                                 msg.sender, _shipper,
                                 _distributor);
        }
 
    function getManufacturedMedicineCountManufacturer(address _manufacturer)
      public view returns(uint)
    {
            require(roles(Admin(admin).getRole(_manufacturer)) ==
                    roles.manufacturer,
            "Only Manufacturer is allowed to call this");
            return ManufacturedMedicine[_manufacturer].length;
    }
 
    function getManufacturedMedicineIdByIndexManufacturer(uint index,
                                                          address _manufacturer)
      public view returns(address)
    {
            require(roles(Admin(admin).getRole(_manufacturer)) ==
                    roles.manufacturer,
            "Only Manufacturer is allowed to call this");
            return ManufacturedMedicine[_manufacturer][index];
    }
 
    function setHash(string memory _hash) public
    {
            Hash[msg.sender] = _hash;
    }
 
    function getHash() public view returns(string memory)
    {
            return Hash[msg.sender];
    }

Distributor

Below is the solidity program to implement the above user role:




// Solidity program to implement
// the above approach
mapping(address=>address[]) MedicineBatchRetailer;
     enum salestatus
     {
        notfound,
        atretailer,
        sold,
        expire,
        damaged
    }
 
     mapping(address=>salestatus) sale;
 
     event MedicineStatus(
           address BatchID,
           address indexed Retailer,
           uint status
    );
 
    function medicineReceivedAtRetailer(address _batchId,
                                        address _distributorAddress)
      public
    {
        require(roles(Admin(admin).getRole(msg.sender)) ==
                roles.retailer,
                "Only retailer can access this function");
        Distributor(_distributorAddress).receivePackageRetailer(_batchId,
                                                                msg.sender);
        MedicineBatchRetailer[msg.sender].push(_batchId);
        sale[_batchId] = salestatus(1);
    }
 
    function updateSaleStatus(
             address _batchId,
             uint _status
    ) public
    {
        require(roles(Admin(admin).getRole(msg.sender)) ==
                roles.retailer,
        "Only retailer can update status!");
        require(sale[_batchId] ==
                salestatus.atretailer,
        "Medicine is not at retailer");
        sale[_batchId]=salestatus(_status);
        emit MedicineStatus(_batchId, msg.sender,
                            _status);
    }
 
    function salesInfo(address _batchId) public view returns(uint)
    {
        return uint(sale[_batchId]);
    }
 
    function getBatchesCountRetailer(address _retailer)
      public view returns(uint){
        require(roles(Admin(admin).getRole(_retailer)) ==
                roles.retailer,
                "Only retailer can call this function!");
        return MedicineBatchRetailer[_retailer].length;
    }
 
    function getBatchedIdByIndexRetailer(uint index,
                                         address _retailer)
      public view returns(address){
        require(roles(Admin(admin).getRole(_retailer)) ==
                roles.retailer,
                "Only retailer can call this function!");
        return MedicineBatchRetailer[_retailer][index];
    }
}

Retailer

Below is the solidity program to implement the above user role:




// Solidity program to implement
// the above approach
pragma solidity >=0.5.0 <0.8.6;
 
contract Admin
{
     address public owner;
 
    constructor() public
    {
        owner = msg.sender;
    }
 
    modifier onlyOwner()
    {
        require(msg.sender == owner,
                "sorry!, Only owner is allowed to visit!");
        _;
    }
 
    enum roles
    {
        norole,
        supplier,
        transporter,
        manufacturer,
        distributor,
        retailer,
        revoke
    }
     
    // Events are triggered at every step of way.
    event UserRegister(address indexed EthAddress,
                       string Name);
    event UserRoleRevoked(address indexed EthAddress,
                          string Name, uint Role);
    event UserRoleRessign(address indexed EthAddress,
                          string Name, uint Role);
 
     struct UserInfo
     {
        string name;
        string location;
        address ethAddress;
        roles role;
    }
 
      mapping(address => UserInfo) public UsersDetails;
      address[] users;
 
    function registerUser(
      address EthAddress,
      string memory Name,
      string memory Location,
      uint Role)
      public onlyOwner
      {
        require(UsersDetails[EthAddress].role ==
                roles.norole,
                "User Already registered");
        UsersDetails[EthAddress].name = Name;
        UsersDetails[EthAddress].location = Location;
        UsersDetails[EthAddress].ethAddress = EthAddress;
        UsersDetails[EthAddress].role = roles(Role);
        users.push(EthAddress);
        emit UserRegister(EthAddress, Name);
    }
 
    function revokeRole(address userAddress)
      public onlyOwner
      {
        require(UsersDetails[userAddress].role !=
                roles.norole,
                "user not registered");
        emit UserRoleRevoked(userAddress,
                             UsersDetails[userAddress].name,
                             uint(UsersDetails[userAddress].role));
        UsersDetails[userAddress].role = roles(6);
    }
 
    function reassignRole(address userAddress,
                          uint Role)
      public onlyOwner
      {
          require(UsersDetails[userAddress].role !=
                  roles.norole,
                  "User not registered");
        UsersDetails[userAddress].role = roles(Role);
        emit UserRoleRessign(userAddress,
                             UsersDetails[userAddress].name,
                             uint(UsersDetails[userAddress].role));
    }
 
    /***User Section***/
 
   function getUserInfo(address userAddress) public view returns(string memory,
                                              string memory,
                                              address, uint)
   {
       return (
           UsersDetails[userAddress].name,
           UsersDetails[userAddress].location,
           UsersDetails[userAddress].ethAddress,
           uint(UsersDetails[userAddress].role)
       );
   }
 
   function getUsersCount() public view returns(uint count)
   {
       return users.length;
   }
 
   function getUserByIndex(uint index)
     public view returns(string memory,
                         string memory,
                         address,uint)
   {
       return getUserInfo(users[index]);
   }
 
   function getRole(address _address) public view returns(uint)
   {
       return uint(UsersDetails[_address].role);
   }
 
}

Transporter

Below is the solidity program to implement the above user role:




// Solidity program to implement
// the above approach
pragma solidity >=0.5.0 <0.8.6;
 
import "./Admin.sol";
import "./RawMaterial.sol";
import "./Medicine.sol";
import "./Distributor.sol";
 
contract Transporter
{
        enum roles{
        norole,
        supplier,
        transporter,
        manufacturer,
        distributor,
        retailer,
        revoke
    }
 
    address admin;
 
    constructor(address _admin) public
    {
         admin = _admin;
    }
 
    function loadConsignment(
        address batchId,
        uint transporterType,
        address distributorId
    ) public
    {
        require(roles(Admin(admin).getRole(msg.sender)) ==
                roles.transporter,
                "Only transporter can call this function.");
        require(transporterType > 0,
                "Transporter type undefined");
        if(transporterType == 1)
        {
            RawMaterial(batchId).pickPackage(msg.sender);
        }
        else if(transporterType == 2)
        {
            Medicine(batchId).pickPackageDistributor(msg.sender);
        }
        else if(transporterType == 3)
        {
            Distributor(distributorId).pickPackageForRetailer(batchId,
                                                              msg.sender);
        }
    }
}

Output:

Admin Page – All Users

Admin – Create User 

Supplier – Create New Raw Material Page.

Distributor – Page

Refer to this video to get more details about the flow of the project

https://www.geeksforgeeks.org/videos/medical-chain-project/

The project source code can be accessed from here.


Article Tags :