Building a Flutter App for Celo-Based Medical Records Management System

Introduction

In today’s digital age, managing medical records efficiently and securely is a significant concern. Traditional systems have been hindered by issues like data breaches, lack of interoperability, and the inability to manage records in real-time. However, blockchain technology provides an effective solution to these challenges. Through this tutorial, we will leverage the Celo blockchain to build a Medical Records Management System.

Celo, with its robust features and Ethereum compatibility, makes it an excellent choice for developing decentralized applications. We will be using Flutter, a popular cross-platform framework, to build our app, focusing on permissioned access control for ensuring data privacy and security.

By the end of this tutorial, we will create a secure, decentralized, user-friendly system for managing medical records.

Prerequisites

Before we dive into building our Celo-Based Medical Records Management System, you need to be familiar with a few things:

  1. Basic understanding of blockchain technology, specifically the Celo platform. If you’re new to Celo, I recommend going through the “Getting Started with Celo” tutorial first.
  2. Proficiency in Flutter and Dart. This tutorial assumes you can create a basic Flutter app.
  3. Some familiarity with smart contracts, as we will use them to store and retrieve medical data on the blockchain.

Requirements

  1. Flutter SDK: Make sure that you have the latest Flutter SDK installed on your system. If not, you can get it from here.
  2. Dart: Dart is the programming language used with Flutter. It should come bundled with the Flutter SDK, but you can also install it separately from here.
  3. Solidity: We will use Solidity for writing smart contracts.
  4. A Celo Wallet: Make sure to set up a wallet on Celo’s Alfajores Testnet. You can do this by following the steps from the Setting up a Celo Wallet section in this tutorial.

Writing the Smart Contract

First, let’s write the Smart Contract. We’ll use Solidity, a programming language for implementing Smart Contracts on Ethereum-based blockchains such as Celo.

Create a new file named MedicalRecords.sol and paste the following code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MedicalRecords {
    address private owner;

    // Define a struct to represent a patient's medical record
    struct Record {
        string patientName;
        string DOB;
        string bloodType;
    }
    
    struct AdditionalRecord {
        string knownAllergies;
        string medicalConditions;
    }

    // Define two mappings that links a patient ID to their Record and AdditionalRecord
    mapping (string => Record) private records;
    mapping (string => AdditionalRecord) private additionalRecords;

    // Define a modifier that only allows the owner of the contract to execute the function
    modifier onlyOwner {
        require(msg.sender == owner, "Only the contract owner can perform this operation");
        _;
    }

    // The constructor sets the owner of the contract to the sender of the transaction
    constructor() {
        owner = msg.sender;
    }

    // Define a function to add a new Record to the mapping
    function addRecord(
        string calldata patientID, 
        string calldata patientName, 
        string calldata DOB, 
        string calldata bloodType
    ) public onlyOwner {
        // Initialize a new Record
        Record memory newRecord = Record({
            patientName: patientName,
            DOB: DOB,
            bloodType: bloodType
        });
        
        // Store the new Record in the records mapping
        records[patientID] = newRecord;
    }
    
    function addAdditionalRecord(
        string calldata patientID, 
        string calldata knownAllergies, 
        string calldata medicalConditions
    ) public onlyOwner {
        // Initialize a new AdditionalRecord
        AdditionalRecord memory newAdditionalRecord = AdditionalRecord({
            knownAllergies: knownAllergies,
            medicalConditions: medicalConditions
        });
        
        // Store the new AdditionalRecord in the additionalRecords mapping
        additionalRecords[patientID] = newAdditionalRecord;
    }

    // Define a function to retrieve a Record and an AdditionalRecord given a patient ID
    function getRecords(string calldata patientID) public view returns (Record memory, AdditionalRecord memory) {
        // Retrieve the Record from the records mapping
        Record memory record = records[patientID];
        AdditionalRecord memory additionalRecord = additionalRecords[patientID];

        // If the Record doesn't exist, revert the transaction
        if (bytes(record.patientName).length == 0) {
            revert("No record found");
        }

        // Return the Record and AdditionalRecord
        return (record, additionalRecord);
    }
}

This smart contract named MedicalRecords is designed to handle medical records on the blockchain. Here’s a detailed breakdown of its functionality:

  • The contract declares two data structures, Record and AdditionalRecord. These structs hold the necessary details about a patient’s medical record. The Record struct holds the patient’s name, date of birth, and blood type, while the AdditionalRecord holds the patient’s known allergies and medical conditions.
  • The contract uses two mappings, records and additionalRecords, to map a patient’s ID to their corresponding Record and AdditionalRecord respectively.
  • The contract also defines a state variable owner of type address to keep track of the owner of the contract. The owner is initially set to be the address that deploys the contract, as defined in the constructor function.
  • There is a modifier function onlyOwner which restricts certain functions to be executable only by the owner of the contract. This function uses the require statement to enforce the constraint.
  • Two functions, addRecord and addAdditionalRecord allow adding a new Record and AdditionalRecord respectively to the mapping. These functions take in patient details as parameters and construct a new Record or AdditionalRecord, which is then added to the respective mapping. Both these functions are guarded by the onlyOwner modifier, ensuring that only the contract owner can add new records.
  • Finally, the function getRecords allows retrieving both the Record and the AdditionalRecord associated with a given patient ID. This function first checks if the requested record exists in the mapping, and if not, it reverts the transaction. If the record exists, it returns the corresponding Record and AdditionalRecord.

After writing and testing the smart contract, you can deploy it to the Celo network using a deployment tools like Remix, Truffle, or Hardhat or you can check out this tutorial to learn how to deploy a smart contract. You will get a contract address and ABI as a result of the deployment. Keep these handy, as they’ll be necessary for interacting with the contract from the Flutter app.

Building the Flutter UI and Connecting to the Contract

First, we need to clone the flutter code repo by running this command in our terminal:

git clone https://github.com/Qtech11/flutter_celo_medical_records.git

Open the cloned project in your preferred IDE. You should have the following files in it:

In your terminal, run the command below to install all dependencies required for the project:

flutter pub get
  1. In your main.dart file, you have the bottom navigation bar which allows you to navigate to two screens( Workout screen and Weight screen).

  2. The add_patient_screen.dart file contains the Add Patient Screen. The add patient screen is expected to display a form field where you can input the patient details and create a patient record.

  3. The get_record_screen.dart file contains the Get Record Screen. The screen has a single textfield (where you input the patient id) and a button used to fetch the patient record using the id you inputed .

  4. The web3_provider.dart file serves as an intermediary between the logic and UI using the flutter riverpod package for managing the state of the app.

  5. The web3helper.dart file contains the code below:

import 'dart:convert';

import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart';

class Web3Helper {
  late Web3Client _client;

  Web3Helper() {
    Client httpClient = Client();
    _client =
        Web3Client('https://alfajores-forno.celo-testnet.org', httpClient);
  }

  final _contractAddress = EthereumAddress.fromHex('<your-contract-address>');
  final credentials = EthPrivateKey.fromHex(
      "<your-private-key>"); // replace with your celo wallet private key

  static const abi = '<your-contract-abi>'; // Replace these with your actual contract ABI

// Replace these with your actual contract ABI

  final contractABI = json.encode(abi);

  Future<String> addRecord(
    String patientId,
    String patientName,
    String dob,
    String bloodType,
  ) async {
    final contract = DeployedContract(
        ContractAbi.fromJson(contractABI, "MedicalRecords"), _contractAddress);
    final function = contract.function('addRecord');

    final response = await _client.sendTransaction(
      credentials,
      Transaction.callContract(
        contract: contract,
        function: function,
        parameters: [patientId, patientName, dob, bloodType],
      ),
      chainId: 44787,
    );

    while (true) {
      final receipt = await _client.getTransactionReceipt(response);
      if (receipt != null) {
        print('Transaction successful');
        print(receipt);
        break;
      }
      // Wait for a while before polling again
      await Future.delayed(const Duration(seconds: 2));
    }
    return response;
  }

  Future<List> getRecords(String id) async {
    try {
      final contract = DeployedContract(
          ContractAbi.fromJson(contractABI, "MedicalRecords"),
          _contractAddress);
      final function = contract.function('getRecords');

      final response = await _client.call(
        contract: contract,
        function: function,
        params: [id],
      );
      return response[0];
    } catch (e) {
      rethrow;
    }
  }
}

This Dart class named Web3Helper sets up a connection to the Celo Alfajores Testnet and interacts with the MedicalRecords smart contract that we defined previously.

  1. import statements: These are the libraries that our class relies on. We are using the http library to make network requests and web3dart to interact with the Ethereum network (Celo is compatible with Ethereum).
  2. class Web3Helper: This is our main class for interacting with the Celo network and our contract.
  3. late Web3Client _client: Here we declare a late-initialized Web3Client instance. This object will allow us to connect to the Celo network.
  4. Web3Helper(): This is the constructor for our class. We create an HTTP client and then initialize the _client with the URL of the Celo Alfajores Testnet.
  5. _contractAddress and credentials: Here we declare the address of our deployed contract and our wallet credentials. We use these to tell the Web3Client where our contract is and to sign transactions.
  6. abi and contractABI: These variables hold the Application Binary Interface (ABI) of our smart contract. The ABI is a JSON string that describes the contract’s methods and variables. It’s generated when the contract is compiled.
  7. addRecord method: This asynchronous function interacts with the addRecord function in our smart contract. It sends a transaction to the contract with the provided parameters (patientId, patientName, dob, bloodType). After sending the transaction, it waits for the transaction receipt to ensure the transaction was successful.
  8. getRecords method: This function calls the getRecords function in our smart contract. It returns the patient’s records for the given id.

This code provides a practical example of how to interact with a smart contract on the Celo network. The addRecord and getRecords methods demonstrate how to call contract functions, which can be extrapolated to any function in a smart contract.

Remember to handle any potential errors and avoid hardcoding sensitive information like private keys in a real-world production application.

When you debug the app to your Emulator or your device, you should have something of this form:

  1. Add Patient Screen:

  2. Get Record Screen:

  3. A presentation of how it works:

    ezgif.com-optimize (2)

Conclusion

In this tutorial, we successfully created a Celo-Based Medical Records Management System using Flutter and Solidity. We explored essential aspects of blockchain technology, including smart contracts, and permissioned access control to ensure data privacy and security. By integrating these concepts with Flutter, we managed to build a user-friendly application for patients and healthcare providers to manage medical records seamlessly.

Next Steps

Now that you’ve mastered the basics of integrating Celo with Flutter to manage medical records, you can further enhance this system. Some potential improvements might include:

  1. Adding more complex querying capabilities to fetch patient records based on various parameters.
  2. Implementing multi-signature wallets to allow multiple stakeholders (like doctors and pharmacists) to validate changes to a patient’s records.

Keep learning and exploring the limitless opportunities blockchain technology offers!

About the Author

Qudus Olanrewaju is a proficient Mobile developer and technical writer who has a strong interest in blockchain technology and web3. He enjoys building web3 projects and leveraging his distinctive viewpoint to create engaging and insightful content. You can connect with me on Linkedin and check out my latest projects on Github

References

  1. Flutter Documentation
  2. Celo Documentation
  3. Solidity Documentation
  4. Web3dart Package
  5. Source Code
11 Likes

Nice … I look forward to this article.

2 Likes

Fantastic news! Your proposal has landed in this week’s top voted list. As you begin your project journey, remember to align with our community and technical guidelines, ensuring a high quality platform for our developers. Congratulations! :mortar_board: :seedling:

2 Likes

I will be reviewing this

2 Likes

okay @ishan.pathak2711

2 Likes