What it does: Handles deposits for rentals (bikes, tools, rooms). Refunds process automatically unless validated issues exist.
Why it matters: Eliminates disputes and slow returns.
How it works:
Deposit locked at rental start.
Condition reported to oracles and arbitrators.
Automatic refund if no claim filed by deadline.
Partial deductions require evidence.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
/**
* @title Peer-to-Peer Rental Deposits
*
* Model:
* - Owner creates rental agreement
* - Renter posts deposit into escrow
* - Funds locked until rental ends
* - Outcomes:
* 1) Mutual settlement (owner + renter agree)
* 2) Owner claims part/all within a claim window
* 3) If owner does nothing -> renter refunds automatically
*
* This contract intentionally avoids "admin" control to remain neutral.
*/
contract RentalDeposits {
enum RentalStatus {
PendingDeposit,
Active,
Completed,
Refunded,
Claimed
}
struct Rental {
address owner;
address renter;
uint256 depositAmount;
uint256 startTime;
uint256 endTime;
uint256 claimDeadline; // Time after end that owner can claim
RentalStatus status;
}
uint256 public rentalCounter;
mapping(uint256, Rental) public rentals;
event RentalCreated(
uint256 indexed rentalId,
address indexed owner,
address indexed renter,
uint256 depositAmount,
uint256 startTime,
uint256 endTime,
uint256 claimDeadline
);
event DepositPosted(uint256 indexed rentalId, address indexed renter);
event MutualSettlement(
uint256 indexed rentalId,
uint256 toOwner,
uint256 toRenter
);
event RefundToRenter(uint256 indexed rentalId, uint256 amount);
event OwnerClaim(
uint256 indexed rentalId,
uint256 claimedAmount,
uint256 returnedToRenter
);
modifier onlyOwner(uint256 rentalId) {
require(msg.sender == rentals[rentalId].owner, "Not rental owner");
_;
}
modifier onlyRenter(uint256 rentalId) {
require(msg.sender == rentals[rentalId].renter, "Not renter");
_;
}
modifier inStatus(uint256 rentalId, RentalStatus expected) {
require(rentals[rentalId].status == expected, "Invalid status");
_;
}
// -------------------------------------------------
// CREATE RENTAL AGREEMENT
// -------------------------------------------------
function createRental(
address renter,
uint256 depositAmount,
uint256 startTime,
uint256 endTime,
uint256 claimWindowSeconds
) external returns (uint256) {
require(renter != address(0), "Invalid renter");
require(depositAmount > 0, "Deposit must be > 0");
require(endTime > startTime, "Invalid times");
require(claimWindowSeconds >= 1 days, "Claim window too short");
rentalCounter++;
rentals[rentalCounter] = Rental({
owner: msg.sender,
renter: renter,
depositAmount: depositAmount,
startTime: startTime,
endTime: endTime,
claimDeadline: endTime + claimWindowSeconds,
status: RentalStatus.PendingDeposit
});
emit RentalCreated(
rentalCounter,
msg.sender,
renter,
depositAmount,
startTime,
endTime,
endTime + claimWindowSeconds
);
return rentalCounter;
}
// -------------------------------------------------
// RENTER POSTS DEPOSIT
// -------------------------------------------------
function postDeposit(uint256 rentalId)
external
payable
onlyRenter(rentalId)
inStatus(rentalId, RentalStatus.PendingDeposit)
{
Rental storage r = rentals[rentalId];
require(msg.value == r.depositAmount, "Incorrect deposit");
require(block.timestamp = r.endTime, "Rental not ended yet");
require(
toOwner + toRenter == r.depositAmount,
"Must split full deposit"
);
// Settle
r.status = RentalStatus.Completed;
if (toOwner > 0) {
payable(r.owner).transfer(toOwner);
}
if (toRenter > 0) {
payable(r.renter).transfer(toRenter);
}
emit MutualSettlement(rentalId, toOwner, toRenter);
}
// -------------------------------------------------
// OWNER CLAIMS DAMAGES (WITH LIMIT + DEADLINE)
// -------------------------------------------------
function ownerClaim(uint256 rentalId, uint256 claimAmount)
external
onlyOwner(rentalId)
inStatus(rentalId, RentalStatus.Active)
{
Rental storage r = rentals[rentalId];
require(block.timestamp >= r.endTime, "Not ended");
require(block.timestamp <= r.claimDeadline, "Claim window expired");
require(claimAmount 0) {
payable(r.owner).transfer(claimAmount);
}
if (toRenter > 0) {
payable(r.renter).transfer(toRenter);
}
emit OwnerClaim(rentalId, claimAmount, toRenter);
}
// -------------------------------------------------
// AUTOMATIC REFUND (OWNER DID NOTHING)
// -------------------------------------------------
function autoRefund(uint256 rentalId)
external
onlyRenter(rentalId)
inStatus(rentalId, RentalStatus.Active)
{
Rental storage r = rentals[rentalId];
require(block.timestamp > r.claimDeadline, "Too early");
r.status = RentalStatus.Refunded;
payable(r.renter).transfer(r.depositAmount);
emit RefundToRenter(rentalId, r.depositAmount);
}
// -------------------------------------------------
// VIEW HELPERS
// -------------------------------------------------
function getRental(uint256 rentalId)
external
view
returns (
address owner,
address renter,
uint256 depositAmount,
uint256 startTime,
uint256 endTime,
uint256 claimDeadline,
RentalStatus status
)
{
Rental memory r = rentals[rentalId];
return (
r.owner,
r.renter,
r.depositAmount,
r.startTime,
r.endTime,
r.claimDeadline,
r.status
);
}
}
Build and Grow By Nam Le Thanh