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();
}
}
Build and Grow By Nam Le Thanh