Decentralized Mortgage Contract

What it does:
Enables a buyer to purchase property using on-chain mortgage financing, where loan repayment, interest, and collateral enforcement are fully automated by a smart contract.

Why it matters:
Removes banks and paperwork from mortgages, replacing them with transparent, programmable, and trust-minimized lending logic.

How it works:

  • Lender funds the mortgage loan.

  • Buyer locks a down payment and commits to repayments.

  • Monthly installments + interest are enforced on-chain.

  • Property collateral can be liquidated on default.

  • Full repayment releases ownership to the borrower.

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

/**
 * @title DecentralizedMortgage
 * @author Nam
 * @notice Trustless mortgage loan with automated repayments and default handling
 */
contract DecentralizedMortgage {

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

    address public lender;
    address public borrower;

    // -------------------- LOAN TERMS --------------------

    uint256 public propertyPrice;
    uint256 public downPayment;
    uint256 public loanAmount;
    uint256 public interestRate; // annual rate in basis points (e.g. 500 = 5%)
    uint256 public loanDuration; // seconds
    uint256 public installmentInterval; // payment period

    // -------------------- STATE --------------------

    uint256 public loanStartTime;
    uint256 public totalRepaid;
    uint256 public lastPaymentTime;
    bool public loanActive;
    bool public defaulted;
    bool public fullyRepaid;

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

    event LoanFunded(uint256 amount);
    event DownPaymentPaid(uint256 amount);
    event InstallmentPaid(uint256 amount);
    event LoanFullyRepaid();
    event DefaultDeclared();
    event CollateralSeized();

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

    modifier onlyBorrower() {
        require(msg.sender == borrower, "Not borrower");
        _;
    }

    modifier onlyLender() {
        require(msg.sender == lender, "Not lender");
        _;
    }

    modifier activeLoan() {
        require(loanActive && !defaulted, "Loan inactive");
        _;
    }

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

    constructor(
        address _borrower,
        uint256 _propertyPrice,
        uint256 _downPayment,
        uint256 _interestRate,
        uint256 _loanDuration,
        uint256 _installmentInterval
    ) {
        require(_borrower != address(0), "Invalid borrower");
        require(_downPayment < _propertyPrice, "Invalid down payment");

        lender = msg.sender;
        borrower = _borrower;
        propertyPrice = _propertyPrice;
        downPayment = _downPayment;
        loanAmount = _propertyPrice - _downPayment;
        interestRate = _interestRate;
        loanDuration = _loanDuration;
        installmentInterval = _installmentInterval;
    }

    // -------------------- FUNDING --------------------

    /**
     * @notice Lender funds the mortgage loan
     */
    function fundLoan() external payable onlyLender {
        require(!loanActive, "Already funded");
        require(msg.value == loanAmount, "Incorrect amount");

        loanActive = true;
        loanStartTime = block.timestamp;
        lastPaymentTime = block.timestamp;

        emit LoanFunded(msg.value);
    }

    /**
     * @notice Borrower pays down payment
     */
    function payDownPayment() external payable onlyBorrower {
        require(msg.value == downPayment, "Incorrect down payment");
        emit DownPaymentPaid(msg.value);
    }

    // -------------------- REPAYMENT --------------------

    /**
     * @notice Pay mortgage installment
     */
    function payInstallment() external payable onlyBorrower activeLoan {
        require(block.timestamp  interest
            ? msg.value - interest
            : 0;

        totalRepaid += msg.value;
        lastPaymentTime = block.timestamp;

        payable(lender).transfer(msg.value);

        emit InstallmentPaid(msg.value);

        if (totalRepaid >= loanAmount + totalInterest()) {
            fullyRepaid = true;
            loanActive = false;
            emit LoanFullyRepaid();
        }
    }

    /**
     * @notice Calculate total interest over loan duration
     */
    function totalInterest() public view returns (uint256) {
        return (loanAmount * interestRate * loanDuration)
            / (365 days * 10000);
    }

    // -------------------- DEFAULT LOGIC --------------------

    /**
     * @notice Declare default if borrower misses payments
     */
    function declareDefault() external onlyLender activeLoan {
        require(
            block.timestamp > lastPaymentTime + installmentInterval,
            "Payment not overdue"
        );

        defaulted = true;
        loanActive = false;

        emit DefaultDeclared();
    }

    /**
     * @notice Seize collateral after default
     */
    function seizeCollateral() external onlyLender {
        require(defaulted, "Not defaulted");

        payable(lender).transfer(address(this).balance);
        emit CollateralSeized();
    }
}