Dynamic Interest Rate Loan

What it does:
A smart contract loan where the interest rate dynamically adjusts over time based on utilization, repayment behavior, or external market signals.

Why it matters:
Fixed-rate loans ignore real market conditions. Dynamic rates create fairer pricing, incentivize timely repayment, and better manage lender risk — all enforced on-chain.

How it works:

  • A lender funds a loan with a base interest rate.

  • The borrower repays periodically.

  • Interest rate automatically increases if repayments are late.

  • Interest rate decreases when the borrower repays early or consistently.

  • Final repayment amount is calculated fully on-chain.

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

/**
 * @title DynamicInterestRateLoan
 * @author Nam
 * @notice Loan with interest rate adjusted by repayment behavior
 */
contract DynamicInterestRateLoan {

    // -------------------- STATE VARIABLES --------------------

    address public lender;
    address public borrower;

    uint256 public principal;
    uint256 public baseInterest;      // in basis points (e.g. 500 = 5%)
    uint256 public currentInterest;   // dynamically adjusted
    uint256 public totalRepaid;

    uint256 public startTime;
    uint256 public lastPaymentTime;
    uint256 public duration;

    bool public funded;
    bool public closed;

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

    event LoanFunded(address indexed lender, uint256 amount);
    event Repayment(address indexed borrower, uint256 amount);
    event InterestUpdated(uint256 newInterest);
    event LoanClosed();

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

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

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

    modifier loanActive() {
        require(funded && !closed, "Loan inactive");
        _;
    }

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

    constructor(
        address _borrower,
        uint256 _baseInterest,
        uint256 _duration
    ) {
        require(_borrower != address(0), "Invalid borrower");
        require(_baseInterest > 0, "Invalid interest");
        require(_duration > 0, "Invalid duration");

        borrower = _borrower;
        baseInterest = _baseInterest;
        currentInterest = _baseInterest;
        duration = _duration;
    }

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

    /**
     * @notice Lender funds the loan
     */
    function fundLoan() external payable {
        require(!funded, "Already funded");
        require(msg.value > 0, "Zero principal");

        lender = msg.sender;
        principal = msg.value;
        funded = true;

        startTime = block.timestamp;
        lastPaymentTime = block.timestamp;

        payable(borrower).transfer(principal);

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

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

    /**
     * @notice Repay loan (partial or full)
     */
    function repay() external payable onlyBorrower loanActive {
        require(msg.value > 0, "Zero repayment");

        totalRepaid += msg.value;
        payable(lender).transfer(msg.value);

        _adjustInterest();

        lastPaymentTime = block.timestamp;

        emit Repayment(msg.sender, msg.value);

        if (totalRepaid >= totalOwed()) {
            closed = true;
            emit LoanClosed();
        }
    }

    // -------------------- INTEREST LOGIC --------------------

    /**
     * @notice Adjust interest based on repayment behavior
     */
    function _adjustInterest() internal {
        uint256 timeSinceLast = block.timestamp - lastPaymentTime;

        // Late payment → increase interest
        if (timeSinceLast > 30 days) {
            currentInterest += 50; // +0.5%
        }
        // Early or consistent payment → decrease interest
        else if (timeSinceLast  baseInterest) {
            currentInterest -= 25; // -0.25%
        }

        emit InterestUpdated(currentInterest);
    }

    // -------------------- CALCULATION --------------------

    /**
     * @notice Calculate total amount owed
     */
    function totalOwed() public view returns (uint256) {
        uint256 interestAmount =
            (principal * currentInterest * duration) /
            (365 days * 10_000);

        return principal + interestAmount;
    }
}