Blockchain Drug Verification System Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Blockchain Drug Verification System Development
Complex
~1-2 weeks
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1215
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1043
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Development of Blockchain Drug Verification System

Counterfeit medicines are not an abstract problem. The WHO estimates the share of fake drugs on markets of developing countries at 10-30%. In the European Union, Directive 2011/62/EU (Falsified Medicines Directive) requires manufacturers to place a unique serial number and verification code on each package. Blockchain provides concrete advantage over centralized registries: manufacturer, distributor and pharmacy don't trust each other — they need a common immutable ledger without single administrator.

Real implementations: MediLedger (largest pharmaceutical consortium in the US, Pfizer, Genentech, AmerisourceBergen), Track and Trace EU system, pilots on Hyperledger Fabric in India and China. Architectural lessons from these systems allow us to not reinvent the wheel.

Data Requirements and Regulatory Context

Serialization Data on Package

GS1 DataMatrix standard on pharma packaging encodes four attributes (DSCSA in US, FMD in EU):

  • GTIN (Global Trade Item Number) — product identifier
  • Lot number — batch number
  • Expiry date — expiration date
  • Serial number — unique for each package
GS1 Application Identifiers:
(01)04150753537323   — GTIN
(17)270131           — Expiry (YYMMDD)
(10)LOT-A4581        — Lot number
(21)000123456789     — Serial number

DataMatrix scannable string:
]d201041507535373232702310100101-A45812100123456789

Serial number + GTIN = unique key for on-chain record. All other data — attributes of this key.

Data Privacy: Zero-Knowledge or Private Channels

Critical architectural problem. Competing pharmaceutical companies don't want to reveal sales volumes, logistics partners don't reveal routes. On-chain data is public by default. Solutions:

Hyperledger Fabric private data collections. Consortium blockchain with private channels: data for specific transaction visible only to channel participants, only hash stored on public ledger. This is standard solution for corporate consortiums (MediLedger uses this approach).

ZK proofs for verification. Pharmacy proves drug is from legitimate supply chain without revealing specific distributor:

// Verifier contract: checks ZK proof of legitimacy
contract DrugVerifier {
    IVerifier public zkVerifier; // Groth16 or PLONK verifier
    
    // Merkle root of all legitimate serial numbers (updated by regulator)
    bytes32 public legitimacyRoot;
    
    // Pharmacy: prove that S/N is in legitimate tree without revealing S/N
    function verifyDrug(
        bytes calldata proof,
        uint256[2] calldata publicInputs // [nullifier, merkle_root]
    ) external view returns (bool) {
        // publicInputs[0] — nullifier (don't repeat verification of same package)
        // publicInputs[1] — must match legitimacyRoot
        require(publicInputs[1] == uint256(legitimacyRoot), "Wrong root");
        return zkVerifier.verifyProof(proof, publicInputs);
    }
}

Chain of Custody: Transfer of Ownership

Each package movement — custody transfer event. Manufacturer → distributor → pharmacy → patient. Each step must be verified by both parties (sending and receiving).

contract DrugTraceability {
    enum Status { MANUFACTURED, IN_TRANSIT, RECEIVED, DISPENSED, RECALLED }
    
    struct DrugUnit {
        bytes32 serialHash;     // keccak256(GTIN + serial) — not stored openly
        address currentHolder;
        Status status;
        uint256 manufacturedAt;
        uint256 expiryTimestamp;
        bool recalled;
    }
    
    mapping(bytes32 => DrugUnit) public drugs; // serialHash => DrugUnit
    mapping(bytes32 => address[]) public custodyHistory;
    
    // Manufacturer registers package
    function manufacture(
        bytes32 serialHash,
        uint256 expiryTimestamp,
        bytes32 lotMerkleRoot  // Merkle root for lot attribute verification
    ) external onlyManufacturer {
        require(drugs[serialHash].manufacturedAt == 0, "Already registered");
        drugs[serialHash] = DrugUnit({
            serialHash: serialHash,
            currentHolder: msg.sender,
            status: Status.MANUFACTURED,
            manufacturedAt: block.timestamp,
            expiryTimestamp: expiryTimestamp,
            recalled: false
        });
        custodyHistory[serialHash].push(msg.sender);
        emit Manufactured(serialHash, msg.sender, block.timestamp);
    }
    
    // Two-way transfer: sender initiates, receiver confirms
    mapping(bytes32 => address) public pendingTransfer; // serialHash => proposed recipient
    
    function initiateTransfer(bytes32 serialHash, address recipient) external {
        require(drugs[serialHash].currentHolder == msg.sender, "Not holder");
        pendingTransfer[serialHash] = recipient;
        emit TransferInitiated(serialHash, msg.sender, recipient);
    }
    
    function confirmTransfer(bytes32 serialHash) external {
        require(pendingTransfer[serialHash] == msg.sender, "Not recipient");
        drugs[serialHash].currentHolder = msg.sender;
        custodyHistory[serialHash].push(msg.sender);
        delete pendingTransfer[serialHash];
        emit TransferConfirmed(serialHash, msg.sender);
    }
    
    // Drug recall
    function recall(bytes32 serialHash, string calldata reason) external onlyRegulator {
        drugs[serialHash].recalled = true;
        emit Recalled(serialHash, reason, block.timestamp);
    }
}

Physical World Integration

Tamper-Evident Packaging + NFC/QR

Blockchain is useful only if link between physical package and on-chain record is reliable. Three levels of protection:

QR code with DataMatrix — minimum, compliant with FMD. Vulnerability: QR can be copied and glued to counterfeit drug. Helps against crude fakes but not sophisticated attacks.

NFC with cryptographic challenge-response (e.g., NXP NTAG 424 DNA). Chip contains private key in secure memory (not extractable). On scan generates signed challenge — impossible to clone without physical chip access. Manufacturer on release registers chip public key on-chain.

// NFC chip verification (reader side)
async function verifyNFCChip(
  chipPublicKey: string,
  challenge: Buffer,
  signature: Buffer
): Promise<boolean> {
  // Verify chip signature
  const isValidSignature = await verifyECDSA(chipPublicKey, challenge, signature)
  
  // Check public key registration on-chain
  const isRegistered = await contract.isChipRegistered(chipPublicKey)
  
  // Check that chip is not in recalled list
  const isRecalled = await contract.isRecalled(chipPublicKey)
  
  return isValidSignature && isRegistered && !isRecalled
}

Holographic labels + blockchain — hybrid approach for markets without NFC infrastructure.

Off-Chain Data and IPFS

Full batch documentation (Certificate of Analysis, test results) doesn't fit in blockchain. Standard pattern:

  • On-chain: bytes32 documentsIPFSHash — Merkle root or IPFS CID of documents
  • Off-chain: IPFS stores documents
  • Verifier: gets documents via IPFS, checks hash on-chain
struct BatchRecord {
    bytes32 lotNumber;
    address manufacturer;
    uint256 productionDate;
    bytes32 coaIpfsHash;      // Certificate of Analysis
    bytes32 testResultsHash;  // QC test results
    uint32  quantity;
}

Blockchain Choice for Pharmaceuticals

Parameter Public (Ethereum/Polygon) Permissioned (Hyperledger Fabric)
Data availability Public, everyone sees Private channels
Participants Any wallets KYC'd consortium members
Transaction costs Gas (optimize) Practically free
Regulatory compliance Harder (publicity) Easier
Decentralization High Consortium
Speed L2: ~2 sec ~1 sec

Recommendation: for B2B consortium of manufacturers/distributors — Hyperledger Fabric (MediLedger model). For consumer-facing verification (patient checks drug) — public blockchain (Polygon or Arbitrum for gas cost) with privacy-preserving ZK check.

Hyperledger Fabric: Key Concepts

// Chaincode (smart contract) in Go
package main

import (
    "github.com/hyperledger/fabric-contract-api-go/contractapi"
)

type DrugContract struct {
    contractapi.Contract
}

func (c *DrugContract) RegisterDrug(ctx contractapi.TransactionContextInterface,
    serialHash, gtin, lot, expiry string) error {
    
    // Check that authorized manufacturer calls
    mspID, _ := ctx.GetClientIdentity().GetMSPID()
    if !isAuthorizedManufacturer(mspID) {
        return fmt.Errorf("unauthorized: %s", mspID)
    }
    
    // Check for duplicate
    existing, _ := ctx.GetStub().GetState(serialHash)
    if existing != nil {
        return fmt.Errorf("drug %s already registered", serialHash)
    }
    
    drug := Drug{
        SerialHash: serialHash,
        GTIN:       gtin,
        Lot:        lot,
        Expiry:     expiry,
        Holder:     mspID,
        Status:     "MANUFACTURED",
        Timestamp:  time.Now().Unix(),
    }
    
    drugJSON, _ := json.Marshal(drug)
    return ctx.GetStub().PutState(serialHash, drugJSON)
}

Regulatory Interfaces

Regulator (FDA, EMA, local authority) must have read access and recall rights. In Hyperledger Fabric: separate channel between manufacturers and regulator. In public blockchain: on-chain role through AccessControl.

// OpenZeppelin AccessControl for roles
bytes32 public constant MANUFACTURER_ROLE = keccak256("MANUFACTURER_ROLE");
bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE");
bytes32 public constant REGULATOR_ROLE = keccak256("REGULATOR_ROLE");

// Only regulator can recall
function recall(bytes32 serialHash, string calldata reason) 
    external onlyRole(REGULATOR_ROLE) { ... }

Development Process

Regulatory analysis (1-2 weeks). Define applicable standards: DSCSA (USA), FMD (EU), local requirements. Pharmaceutical systems fall under validated software requirements (FDA 21 CFR Part 11) — documentation and requirements traceability matrix needed.

Architectural design (1-2 weeks). Blockchain choice (permissioned vs public), privacy model, GS1 data scheme, NFC/QR strategy. Design consortium participant scheme and governance.

Smart contract development (4-6 weeks). Registration, custody transfer, recall contracts. Extended testing: edge cases (package after recall, expired drug transfer, duplicate serial numbers).

Backend integration (4-8 weeks). API for integration with manufacturer ERP systems (SAP, Oracle Pharma), distributor WMS. Batch import for registering thousands of serial numbers simultaneously.

Hardware integration (2-4 weeks). SDK for DataMatrix scanners, NFC readers, integration with existing warehouse equipment. Offline mode for weakly-connected networks (pharmacies in remote regions).

Audit and validation (4-6 weeks). Smart contract audit (mandatory — drug data affects human health). Validation documentation for regulatory compliance (IQ/OQ/PQ per GAMP5).

Timeline Guidelines

MVP for pilot with one manufacturer and one pharmacy chain — 3-4 months. Production system for consortium with full regulatory compliance — 9-15 months. Project complexity determined not by blockchain part but by legacy ERP system integration and regulatory validation.