Open In App

Med Chain – Solidity Project to Solve illegal Supply of Drugs

Last Updated : 02 May, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

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:

  • It can be used to track the vaccines for covid-19.
  • It can be used to track the international medicine transfer.
  • It can be used to keep track of how medicine is performing in the market.

Features:

  • Create a raw material and track its progress.
  • View the previously created raw materials.
  • Create a medicine using the created raw materials.
  • Keep track of the medicine being exported.
  • Distribute the medicine to the retailers.
  • Update the status of the medicine (sold, expired, damaged, not received, etc.)
  • keep track of the medicine cycle every step of the way.

Roles & Smart Contracts

Admin:

  • Registers a new user (Supplier, Transporter, Manufacturer, Distributor, Retailer).
  • Reassign roles to existing users.
  • Revoke roles of existing users.
  • keep track of the users.

Below is the solidity code for the above user role:

Solidity




// 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

  • Creates a new raw material.
  • Keeps track of previously created raw materials.

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

Solidity




// 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

  • Uses the received raw material to create new medicine.
  • Registers the new medicine.
  • Exports the new medicine to the distributor.
  • Keeps track of the existing medicines.

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

Solidity




// 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

  • Receive the medicine from the manufacturer.
  • Distributes the medicine to the retailers.
  • Keeps track of the distributed medicine.

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

Solidity




// 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

  • Receives medicine from the distributor.
  • Sells the medicine.
  • Updates status of the medicine.
  • Keeps track of the sold medicine.

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

Solidity




// 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

  • Transports the medicine from supplier to manufacturer.
  • Transports the medicine from the manufacturer to the distributor.
  • Transports the medicine from distributor to retailer.

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

Solidity




// 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:

All users

Admin Page – All Users

Create user

Admin – Create User 

Create a new package

Supplier – Create New Raw Material Page.

sent packages

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.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads