Celo-based Insurance Platform

Celo-based Insurance Platform https://celo.academy/uploads/default/optimized/2X/5/5f9596ce60307e8399fef3d3a88e75ab9b4faacc_2_1024x576.png
none 0.0 0

Introduction

In the world of finance, insurance is a key player. Traditional insurance systems, however, often suffer from bureaucratic processes and a lack of transparency. By leveraging blockchain technology, we can create an insurance system that is not only efficient but also transparent. In this tutorial, we’ll guide you on how to create a simple blockchain-based insurance platform on the Celo network. With Solidity for our smart contracts, JavaScript for general programming, and React and Tailwind Components for our user interface, we’ll automate claim processing and payout. Let’s dive in!

Prerequisites

Before proceeding, you should have a basic understanding of blockchain technology, specifically the Celo network. You should be comfortable with programming in JavaScript and have experience with Solidity for smart contract development. Familiarity with React and Tailwind CSS will be advantageous for the frontend development. Completion of the tutorial “Connect to Celo using hardhat” is also recommended.

Requirements

Before we begin, ensure that you have the following tools installed:

  1. Node.js, version 12.0.1 or later
  2. Metamask browser extension for interacting with the Celo network
  3. Truffle for developing our smart contracts
  4. React for building our user interface
  5. A Celo Faucet Account

To get a Celo test account, you can follow these steps:

  1. Visit the Celo Faucet at Fund Your Testnet Account
    2. Click on “Connect Celo Extension Wallet” and follow the prompts to connect your Celo Extension Wallet.
    3. After connecting your wallet, you will see your account address.
    4. Click “Request Funds” to receive test tokens (cGLD and cUSD) on the Alfajores testnet. The faucet will send test tokens to your account.
    5. Make sure your Celo Extension Wallet is set to the Alfajores Testnet.

Now you can use this test account in the tutorial. Ensure that you’re interacting with the Alfajores Testnet when working on your project.

Getting Started: Setting Up Our Development Environment

First, we need to set up our development environment. We will begin by installing the necessary dependencies for our project. Create a new folder for the project and initialize it with Node.js and NPM:

mkdir celo-insurance && cd celo-insurance
npm init -y

Initialize a new Truffle project:

truffle init

Install the OpenZeppelin Contracts library:

npm install @openzeppelin/contracts

Building Our Smart Contracts

Our insurance platform will rely on two main smart contracts: the InsuranceProvider contract and the Policy contract.
The InsuranceProvider contract will handle the creation of new policies, storing them, and handling payouts. The Policy contract will represent an individual insurance policy and will handle the specifics of each policy, such as the policyholder’s information, the policy terms, and claim filing.

The InsuranceProvider Contract

First, we’ll create our InsuranceProvider contract. This contract will manage the creation of new policies and handle the storage of policy contracts. Let’s define the basic structure:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./Policy.sol";
contract InsuranceProvider is Ownable {
    uint256 public policyCounter;
    mapping(uint256 => Policy) public policies;
    event PolicyCreated(uint256 policyId, address policyAddress);
    function createPolicy(
        address policyholder,
        uint256 premium,
        uint256 coverageAmount
    ) public onlyOwner returns (uint256) {
        policyCounter++;
        Policy policy = new Policy(policyholder, premium, coverageAmount);
        policies[policyCounter] = policy;
        emit PolicyCreated(policyCounter, address(policy));
        return policyCounter;
    }
}

In this contract, we’re using the OpenZeppelin library for the Ownable contract which restricts certain functions such as creating a policy to only the owner of the contract.

The createPolicy function allows the owner to create a new policy contract. It takes the policyholder’s address and the premium and coverage amount for the policy. It then increments the policyCounter, creates a new Policy contract, and stores it in our policies mapping.

We also emit a PolicyCreated event every time a new policy is created. This allows front-end applications to listen for this event and react accordingly.

The Policy Contract

Next, let’s create our Policy contract. This contract will handle policy specifics such as the policyholder’s information, policy terms, and claim filing.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "@openzeppelin/contracts/access/AccessControl.sol";
contract Policy is AccessControl {
    bytes32 public constant POLICYHOLDER_ROLE = keccak256("POLICYHOLDER_ROLE");
    address public insuranceProvider;
    uint256 public premium;
    uint256 public coverageAmount;
    uint256 public createdAt;
    bool public active;
    event ClaimFiled(uint256 amount);
    event PolicyActivated();
    constructor(
        address policyholder,
        uint256 _premium,
        uint256 _coverageAmount
    ) {
        _setupRole(POLICYHOLDER_ROLE, policyholder);
        insuranceProvider = msg.sender;
        premium = _premium;
        coverageAmount = _coverageAmount;
        active = false;
        createdAt = block.timestamp;
    }
    function fileClaim(uint256 amount) public {
        require(hasRole(POLICYHOLDER_ROLE, msg.sender), "Caller is not the policyholder");
        require(active, "Policy is not active");
        require(amount <= coverageAmount, "Claim amount exceeds coverage amount");
        coverageAmount -= amount;
        
        emit ClaimFiled(amount);
    }
    function activate() public {
        require(msg.sender == insuranceProvider, "Caller is not the insurance provider");
        require(!active, "Policy is already active");
        active = true;
        emit PolicyActivated();
    }
}

In this contract, we’re using OpenZeppelin’s AccessControl contract to manage roles. We define a POLICYHOLDER_ROLE which will be assigned to the policyholder upon creation of the policy.

The fileClaim function allows the policyholder to file a claim, as long as the policy is active and the claim amount does not exceed the coverage amount. If a claim is successfully filed, the coverage amount is reduced by the claim amount, and a ClaimFiled event is emitted.

The activate function allows the insurance provider to activate a policy. This can be done only by the insurance provider, and only if the policy is not already active. Upon successful activation, a PolicyActivated event is emitted.

Compiling and Deploying the Smart Contract to the Celo Test Network

  1. Create a new file migrations/2_deploy_contracts.js and add the following code:

    const InsuranceProvider = artifacts.require("InsuranceProvider");
     module.exports = function(deployer) {
       deployer.deploy(InsuranceProvider);
     };
    
  2. Update the truffle-config.js file to include the Celo-Alfajores network configuration:

  const ContractKit = require("@celo/contractkit");
  const Web3 = require("web3");
  
  const web3 = new Web3("https://alfajores-forno.celo-testnet.org");
  const kit = ContractKit.newKitFromWeb3(web3);
  
  // Add your private key and account address
  const privateKey = "your_private_key";
  const accountAddress = "your_account_address";
  
  kit.addAccount(privateKey);
  
  module.exports = {
    networks: {
      development: { host: "127.0.0.1", port: 7545, network_id: "*" },
      alfajores: {
        provider: kit.connection.web3.currentProvider,
        network_id: 44787,
        from: accountAddress,
        gas: 6721975,
        gasPrice: 20000000000,
      },
    },
    compilers: {
      solc: {
        version: "0.8.0",
      },
    },
  };
  1. Compile the smart contract

Run the following command to compile the smart contract:

truffle compile
  1. Deploy the smart contract to the Celo network

Run the following command to deploy the MedicalRecord smart contract to the Celo network:

truffle migrate --network alfajores

After the deployment is successful, you will see the smart contract address in the console output. Take note of the deployed contract address for future use.

Frontend Application with React and Tailwind CSS

Now that we have our smart contracts, let’s create a frontend application to interact with them. We will use React for our application framework and Tailwind CSS for our styling.

First, let’s create our React application and install the necessary dependencies.

npx create-react-app insurance-app
cd insurance-app
npm install ethers @openzeppelin/contracts tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

Next, initialize Tailwind CSS by creating a configuration file:

npx tailwindcss init

In the tailwind.config.js file, replace the contents with the following:

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

In src/index.css, add Tailwind’s base, components, and utilities directives:

import { ethers } from 'ethers';
import InsuranceProvider from './InsuranceProvider.json';
import Policy from './Policy.json';
import { useState, useEffect } from 'react';
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = provider.getSigner();
const InsuranceProviderAddress = '0x36Bf04e9595E08bc6b3B5FBcF0CEd532a2f071a8';
const insuranceProvider = new ethers.Contract(InsuranceProviderAddress, InsuranceProvider.abi, signer);
function App() {
  const [policies, setPolicies] = useState([]);
  const [premium, setPremium] = useState();
  const [coverage, setCoverage] = useState();
  const [claimAmount, setClaimAmount] = useState();
  const [selectedPolicyId, setSelectedPolicyId] = useState();
  useEffect(() => {
    async function fetchPolicies() {
      const policyCount = await insuranceProvider.getPolicyCount();
      
      const policyPromises = Array.from({length: policyCount}, (_, i) => insuranceProvider.policies(i));
      const policyAddresses = await Promise.all(policyPromises);
      
      const policyObjects = policyAddresses.map(address => {
        return {
          id: address,
          contract: new ethers.Contract(address, Policy.abi, signer)
        }
      });
      setPolicies(policyObjects);
    }
    
    fetchPolicies();
  }, []);
  async function createPolicy() {
    try {
      const tx = await insuranceProvider.createPolicy(signer.getAddress(), premium, coverage);
      await tx.wait();
      
      alert('Policy created');
    } catch (error) {
      console.error('An error occurred while creating the policy:', error);
    }
  }
  
  async function fileClaim() {
    try {
      const selectedPolicy = policies.find(policy => policy.id === selectedPolicyId);
      const tx = await selectedPolicy.contract.fileClaim(claimAmount);
      await tx.wait();
      
      alert('Claim filed');
    } catch (error) {
      console.error('An error occurred while filing the claim:', error);
    }
  }
  async function activatePolicy() {
    try {
      const selectedPolicy = policies.find(policy => policy.id === selectedPolicyId);
      const tx = await selectedPolicy.contract.activate();
      await tx.wait();
      
      alert('Policy activated');
    } catch (error) {
      console.error('An error occurred while activating the policy:', error);
    }
  }
  return (
    <div>
      <input type="number" value={premium} onChange={e => setPremium(e.target.value)} placeholder="Premium" />
      <input type="number" value={coverage} onChange={e => setCoverage(e.target.value)} placeholder="Coverage" />
      <button onClick={createPolicy}>Create Policy</button>
      
      <select value={selectedPolicyId} onChange={e => setSelectedPolicyId(e.target.value)}>
        {policies.map(policy => <option key={policy.id} value={policy.id}>{policy.id}</option>)}
      </select>
      
      <input type="number" value={claimAmount} onChange={e => setClaimAmount(e.target.value)} placeholder="Claim Amount" />
      <button onClick={fileClaim}>File Claim</button>
      <button onClick={activatePolicy}>Activate Policy</button>
      
      {policies.map(policy => {
        return (
          <div key={policy.id}>
            <h2>Policy: {policy.id}</h2>
            <button onClick={() => checkPolicyState(policy)}>Check Status</button>
            <div id={`policy-${policy.id}`}></div>
          </div>
        );
      })}
    </div>
  );
  async function checkPolicyState(policy) {
    try {
      const isActive = await policy.contract.isActive();
      const status = isActive ? 'Active' : 'Inactive';
      const claimAmount = await policy.contract.claimAmount();
      const statusElement = document.getElementById(`policy-${policy.id}`);
      statusElement.textContent = `Status: ${status}, Claim Amount: ${claimAmount.toString()}`;
    } catch (error) {
      console.error('An error occurred while checking the policy status:', error);
    }
  }
}
export default App;

This is a basic example and a real production application would have more features such as a form to input the premium and coverage amounts, a list of all the created policies, and error handling, but this serves as a good starting point.

In this version of the application, users can create new policies, specify their premium and coverage amounts, file claims, activate their policies, and view their policy details. All created policies are tracked, and the status of each policy can be individually viewed.
Each policy is represented with its ID and has its own status checking button. Clicking the button will show the current status of the policy and the claim amount.

To test the application, run the following command in your terminal:

npm start

This will open a browser window with the application.

Conclusion

Congratulations! You have successfully built a basic insurance platform on the Celo network using Solidity for smart contracts, JavaScript for interacting with the blockchain, and React for the frontend. You learned how to create an insurance policy, file a claim, and check the status of a policy.

Next Steps

If you want to delve deeper into the world of DApp development, here are some suggestions:

  • Refactor the contract to include more complex policy structures and claims processing mechanisms.
  • Integrate a database to track more information about policies and claims.
  • Implement a frontend library like Redux for better state management.
  • Learn about the gas costs of Ethereum transactions and how you can optimize your smart contracts to save gas.

References

This tutorial was created using resources from the official documentation of Celo SDK, Solidity, Javascript, and React. Special thanks to the open-source community for providing such comprehensive resources.
Finally, you can access this tutorial code repo here.

About the Author

Oluwalana is a blockchain developer and technical writer, experienced in creating decentralized applications on Ethereum and Celo platforms. With a passion for knowledge-sharing, Oluwalana has authored various tutorials and articles on blockchain and other emerging technologies. Follow me on Twitter for insights on blockchain and emerging tech. For professional inquiries, kindly connect with me on LinkedIn and explore my work on GitHub.

6 Likes

I find this interesting. What is your plan to regulate policy with this protocol?

2 Likes

Looking forward to this

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:

3 Likes

i’ll be reviewing this @Lanacreates

2 Likes