What it does:
A smart contract that automatically pulls rent payments on schedule and enforces penalties when payments are late, removing friction and disputes between landlord and tenant.
Why it matters:
Missed rent and manual reminders create stress and conflict. This contract enforces rent discipline programmatically, ensuring fairness and predictability for both sides.
How it works:
Tenant pre-funds the contract or approves spending.
Rent is automatically collected each rental period.
Late or insufficient balances trigger penalties.
Landlord can withdraw collected rent.
All payment activity is fully transparent on-chain.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title AutomatedRentPaymentAndPenalty
* @author Nam
* @notice Automated rent collection with penalties for late payments
*/
contract AutomatedRentPaymentAndPenalty {
// -------------------- STATE VARIABLES --------------------
address public landlord;
address public tenant;
uint256 public rentAmount; // Rent per period
uint256 public rentInterval; // Interval (e.g. 30 days)
uint256 public latePenalty; // Penalty per missed period
uint256 public lastPayment;
uint256 public escrowBalance;
bool public active;
// -------------------- EVENTS --------------------
event Funded(address indexed tenant, uint256 amount);
event RentCollected(uint256 amount);
event PenaltyApplied(uint256 penalty);
event Withdrawn(address indexed landlord, uint256 amount);
event AgreementTerminated();
// -------------------- MODIFIERS --------------------
modifier onlyTenant() {
require(msg.sender == tenant, "Not tenant");
_;
}
modifier onlyLandlord() {
require(msg.sender == landlord, "Not landlord");
_;
}
modifier agreementActive() {
require(active, "Agreement inactive");
_;
}
// -------------------- CONSTRUCTOR --------------------
constructor(
address _tenant,
uint256 _rentAmount,
uint256 _rentInterval,
uint256 _latePenalty
) {
require(_tenant != address(0), "Invalid tenant");
require(_rentAmount > 0, "Invalid rent");
require(_rentInterval > 0, "Invalid interval");
landlord = msg.sender;
tenant = _tenant;
rentAmount = _rentAmount;
rentInterval = _rentInterval;
latePenalty = _latePenalty;
}
// -------------------- START & FUND --------------------
/**
* @notice Tenant funds escrow and activates agreement
*/
function start() external payable onlyTenant {
require(!active, "Already active");
require(msg.value >= rentAmount, "Insufficient funding");
escrowBalance += msg.value;
lastPayment = block.timestamp;
active = true;
emit Funded(msg.sender, msg.value);
}
/**
* @notice Add more funds to escrow
*/
function fund() external payable onlyTenant agreementActive {
require(msg.value > 0, "Zero funding");
escrowBalance += msg.value;
emit Funded(msg.sender, msg.value);
}
// -------------------- AUTOMATED COLLECTION --------------------
/**
* @notice Collect rent if interval passed
*/
function collectRent() external agreementActive {
require(
block.timestamp >= lastPayment + rentInterval,
"Not due yet"
);
uint256 periodsMissed =
(block.timestamp - lastPayment) / rentInterval;
uint256 totalDue =
rentAmount * periodsMissed;
uint256 totalPenalty =
latePenalty * (periodsMissed - 1);
uint256 payableAmount =
totalDue + totalPenalty;
require(
escrowBalance >= payableAmount,
"Insufficient escrow"
);
escrowBalance -= payableAmount;
lastPayment = block.timestamp;
payable(landlord).transfer(payableAmount);
emit RentCollected(totalDue);
if (totalPenalty > 0) {
emit PenaltyApplied(totalPenalty);
}
}
// -------------------- LANDLORD WITHDRAW --------------------
/**
* @notice Withdraw remaining funds (lease end)
*/
function withdraw(uint256 _amount)
external
onlyLandlord
{
require(_amount <= address(this).balance, "Too much");
payable(landlord).transfer(_amount);
emit Withdrawn(msg.sender, _amount);
}
// -------------------- TERMINATION --------------------
/**
* @notice Terminate agreement
*/
function terminate()
external
onlyLandlord
agreementActive
{
active = false;
emit AgreementTerminated();
}
// -------------------- VIEW FUNCTIONS --------------------
function nextPaymentDue() external view returns (uint256) {
return lastPayment + rentInterval;
}
}
Build and Grow By Nam Le Thanh