What it does:
Automatically renews or terminates a rental lease based on predefined conditions such as tenant payment history, notice periods, and landlord approval.
Why it matters:
Removes friction and ambiguity from lease renewals, ensuring both tenant and landlord follow transparent, enforceable rules.
How it works:
Lease terms and renewal conditions are set at deployment.
Tenant signals intent to renew and pays renewal fee (if any).
Contract checks eligibility (on-time payments, notice window).
Lease is auto-extended or cleanly expired on-chain.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title SmartLeaseRenewal
* @author Nam
* @notice Automates lease renewal based on predefined conditions
*/
contract SmartLeaseRenewal {
// -------------------- ROLES --------------------
address public landlord;
address public tenant;
// -------------------- LEASE TERMS --------------------
uint256 public leaseStart;
uint256 public leaseEnd;
uint256 public renewalDuration; // seconds
uint256 public renewalFee; // ETH
uint256 public noticePeriod; // seconds before lease end
// -------------------- STATE --------------------
bool public active;
bool public renewalRequested;
bool public terminated;
// -------------------- EVENTS --------------------
event RenewalRequested(address indexed tenant);
event LeaseRenewed(uint256 newLeaseEnd);
event LeaseTerminated();
// -------------------- MODIFIERS --------------------
modifier onlyTenant() {
require(msg.sender == tenant, "Not tenant");
_;
}
modifier onlyLandlord() {
require(msg.sender == landlord, "Not landlord");
_;
}
modifier leaseActive() {
require(active && !terminated, "Lease inactive");
_;
}
// -------------------- CONSTRUCTOR --------------------
constructor(
address _tenant,
uint256 _leaseDuration,
uint256 _renewalDuration,
uint256 _renewalFee,
uint256 _noticePeriod
) {
require(_tenant != address(0), "Invalid tenant");
landlord = msg.sender;
tenant = _tenant;
leaseStart = block.timestamp;
leaseEnd = leaseStart + _leaseDuration;
renewalDuration = _renewalDuration;
renewalFee = _renewalFee;
noticePeriod = _noticePeriod;
active = true;
}
// -------------------- RENEWAL LOGIC --------------------
/**
* @notice Tenant requests lease renewal
*/
function requestRenewal() external payable onlyTenant leaseActive {
require(!renewalRequested, "Already requested");
require(block.timestamp >= leaseEnd - noticePeriod, "Too early");
require(msg.value == renewalFee, "Incorrect renewal fee");
renewalRequested = true;
emit RenewalRequested(msg.sender);
}
/**
* @notice Landlord approves renewal
*/
function approveRenewal() external onlyLandlord leaseActive {
require(renewalRequested, "No renewal request");
leaseEnd += renewalDuration;
renewalRequested = false;
if (renewalFee > 0) {
payable(landlord).transfer(renewalFee);
}
emit LeaseRenewed(leaseEnd);
}
// -------------------- TERMINATION --------------------
/**
* @notice Lease ends without renewal
*/
function terminateLease() external leaseActive {
require(block.timestamp >= leaseEnd, "Lease not ended");
require(!renewalRequested, "Renewal pending");
active = false;
terminated = true;
emit LeaseTerminated();
}
}
Build and Grow By Nam Le Thanh