Solidity Smart Contracts Walk-through Series Part-2
This is part 2 of Smart contract walk-through series. In the following post I will give you an in-depth overview over the technical implementation details of our property rental smart contract. Code repository can be found here.
Property on rent use case ::
Overall use case is very simple. Users will register themselves as a prospect against a given property. Property owner will decide which user is going to be the tenant. Tenant will pay the rent as per the agreed due date. Rent amount to be stored in the contract. Owner can withdraw the same rent from contract. In case tenant has not paid the rent by due date, owner is allowed to raise a warning against tenant. Owner is allowed to raise warning in an interval of at least 2 days. In case tenant has crossed the warning limit, owner can dismiss tenant from property.
Let’s start …
Here is our data structure defined :
Here we have defined the Property struct which will keep record of property details such as name, address, property rented or not, rent amount, rent interval, rent due date, warning count, warning limit & tenant wallet address. We have MonthlyRentStatus struct which will help us to store the rent status for each month. We also have various mappings — months, tenantRegistry & rent paid status.
We have events defined that will help us to log the successful transactions. We are setting property owner , property details & months mapping in constructor itself. Constructor gets invoked only once (when the contract gets deployed).
Shown above are various modifiers to isolate & differentiate the various functionalities of our contract.
Any user can express his/her interest for property on rent by invoking registerAsTenant method. If the property is not rented, it will set the tenantRegistry mapping for given user. Property owner will confirm which user should become the tenant by invoking confirmTenant method with input as respective user wallet address. This will finalise the tenant , mark the property rented status as true & will set the rent due date based on rent interval.
Note — All date based calculations over here are based on unix timestamp. now is the keyword which gives us the timestamp of the block containing our transaction. However this is not the accurate timestamp but it will give time under permissible range.
Method payRent will allow tenant to pay the rent for a given month. Please note that rent will be accepted only if the amount sent is equal to the rent amount to be paid.It will also set the next due date & resets the tenant warning to 0 if any.
Note- If function parameters (return parameters as well) are of type struct, array, mapping or string , then one should clearly indicate their data location— either memory or storage. If function is external, one should make data location as calldata. For more info on how memory & storage model works checkout here.
Method getRentStatus will allow anyone to check the rent status of any given month.
Note- Any function scope variable of type struct should clearly indicate its data location — memory or storage , as this helps compiler to take the transaction based decisions. Note that in getRentStatus method we are returning each field as returning complete struct is not possible. Solidity implements struct only as a loose bag of variables.
withdrawRent will allow owner to withdraw the monthly rent amount from contract address. It will also reset the rentInStore mapping to 0 for respective month as owner should not be allowed to withdraw rent twice for same month.
Owner can warn tenant about pending rent only if –
- Tenant has not paid the rent & due date is reached.
- Last warning if any was raised atleast 2 days before(now — warningTime >172800000).
A warning event will be triggered which can be listened by user interface using web3 api so as to warn the tenant about pending rent. Also warning count will be incremented.
Owner can also dismiss the tenant in case warning limit has been reached. Calling dismissTenant method also resets the property rented status to false.