Property Insurance Payout Contract

What it does:
Automatically manages property insurance claims and releases payouts to property owners when predefined damage or incident conditions are met.

Why it matters:
Removes slow, opaque insurance claim processes by enforcing transparent rules, reducing disputes, and ensuring faster, trustless payouts.

How it works:

  • Insurance terms and coverage limits are set at deployment

  • Property owner pays insurance premiums into the contract

  • A claim is submitted with an incident reason

  • Authorized assessor verifies the claim on-chain

  • Contract checks coverage and payout eligibility

  • Approved claims trigger automatic payout to the owner

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

/**
 * @title PropertyInsurancePayout
 * @author Nam
 * @notice On-chain property insurance claim and payout contract
 */
contract PropertyInsurancePayout {

    // -------------------- ROLES --------------------

    address public insurer;
    address public propertyOwner;
    address public assessor;

    // -------------------- INSURANCE TERMS --------------------

    uint256 public coverageAmount;
    uint256 public premiumPaid;

    // -------------------- CLAIM STATE --------------------

    bool public policyActive;
    bool public claimSubmitted;
    bool public claimApproved;
    bool public payoutCompleted;

    // -------------------- EVENTS --------------------

    event PremiumPaid(address indexed owner, uint256 amount);
    event ClaimSubmitted(string reason);
    event ClaimApproved(uint256 payoutAmount);
    event PayoutExecuted(address indexed owner, uint256 amount);

    // -------------------- MODIFIERS --------------------

    modifier onlyOwner() {
        require(msg.sender == propertyOwner, "Not property owner");
        _;
    }

    modifier onlyInsurer() {
        require(msg.sender == insurer, "Not insurer");
        _;
    }

    modifier onlyAssessor() {
        require(msg.sender == assessor, "Not assessor");
        _;
    }

    modifier policyValid() {
        require(policyActive, "Policy inactive");
        _;
    }

    // -------------------- CONSTRUCTOR --------------------

    constructor(
        address _propertyOwner,
        address _assessor,
        uint256 _coverageAmount
    ) {
        require(_propertyOwner != address(0), "Invalid owner");
        require(_assessor != address(0), "Invalid assessor");

        insurer = msg.sender;
        propertyOwner = _propertyOwner;
        assessor = _assessor;
        coverageAmount = _coverageAmount;
    }

    // -------------------- PREMIUM LOGIC --------------------

    /**
     * @notice Property owner pays insurance premium
     */
    function payPremium() external payable onlyOwner {
        require(!policyActive, "Policy already active");
        require(msg.value > 0, "Invalid premium");

        premiumPaid = msg.value;
        policyActive = true;

        emit PremiumPaid(msg.sender, msg.value);
    }

    // -------------------- CLAIM LOGIC --------------------

    /**
     * @notice Submit an insurance claim
     */
    function submitClaim(string calldata _reason)
        external
        onlyOwner
        policyValid
    {
        require(!claimSubmitted, "Claim already submitted");

        claimSubmitted = true;
        emit ClaimSubmitted(_reason);
    }

    /**
     * @notice Approve claim after assessment
     */
    function approveClaim()
        external
        onlyAssessor
        policyValid
    {
        require(claimSubmitted, "No claim submitted");
        require(!claimApproved, "Already approved");

        claimApproved = true;
        emit ClaimApproved(coverageAmount);
    }

    // -------------------- PAYOUT LOGIC --------------------

    /**
     * @notice Execute insurance payout
     */
    function executePayout()
        external
        onlyInsurer
        policyValid
    {
        require(claimApproved, "Claim not approved");
        require(!payoutCompleted, "Payout completed");
        require(address(this).balance >= coverageAmount, "Insufficient funds");

        payoutCompleted = true;
        policyActive = false;

        payable(propertyOwner).transfer(coverageAmount);
        emit PayoutExecuted(propertyOwner, coverageAmount);
    }
}