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;
}
}