WEEK 3 (DAY 1): My first smart contract
a warm welcome into the world of solidity. this is where it gets interesting and logical. solidity is one of the programming languages designed for developing smart contracts that run on Ethereum. it is a strictly typed language (i.e. you have to explicitly define data types and size for both variables and functions).
```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TimeLogging {
// Struct to hold the attendance details
struct Attendance {
string name;
uint timeLoggedAt;
}
// Mapping to store attendance records by user address
mapping (address => Attendance) attendanceLog;
// Function to log time with a daily check
function logTime(string memory _name) public {
// Check if the user has already logged time today
require(!hasLoggedToday(), "You have already logged time today.");
// Log attendance details if no log exists for today
Attendance memory newAttendance = Attendance({
name: _name,
timeLoggedAt: block.timestamp
});
attendanceLog[msg.sender] = newAttendance;
}
// Function to check if a user has already logged time for the current day
function hasLoggedToday() internal view returns (bool) {
Attendance storage userAttendance = attendanceLog[msg.sender];
// If the user has not logged any time before
if (userAttendance.timeLoggedAt == 0) {
return false;
}
// Calculate the difference in days
uint lastLoggedDay = userAttendance.timeLoggedAt / 1 days;
uint currentDay = block.timestamp / 1 days;
return lastLoggedDay == currentDay;
}
function getAttendance(address _user) public view returns (Attendance memory) {
return attendanceLog[_user];
}
}
```
**CODE BREAKDOWN**
```
// SPDX-License-Identifier: MIT
```
**License Declaration:**
This line declares the contract is licensed under the MIT License, making it open-source and reusable.
```
pragma solidity ^0.8.0;
```
**Pragma Directive:**
Specifies the version of Solidity to be used. In this case, it ensures that the contract will only compile with Solidity version 0.8.0 or higher, protecting it from incompatibilities with earlier versions.
```
contract TimeLogging {
```
**Contract Declaration:**
This begins the declaration of the `TimeLogging` smart contract. A smart contract is similar to a class in other programming languages and contains state variables and functions that define its behavior.
```
struct Attendance {
string name;
uint timeLoggedAt;
}
```
**Struct Definition:**
Here we define a struct named Attendance to represent the details we want to store for each user.
* `string name`: The user's name.
* `uint timeLoggedAt`: The timestamp of when the user logged their attendance.
```
mapping (address => Attendance) public attendanceLog;
```
Mapping Declaration:
This line creates a mapping that stores attendance records for each user. The key is the user's Ethereum address, and the value is the Attendance struct containing the user’s details and the time they logged in.
The public keyword makes the mapping accessible externally, meaning anyone can view it.
```
function logTime(string memory _name) public {
```
**Function Declaration:**
This function logTime() allows a user to log their attendance by providing their name.
* string memory _name: The user's name is passed as an argument to the function. The keyword memory specifies that the string is temporary and only needed during execution.
```
require(!hasLoggedToday(), "You have already logged time today.");
```
**Require Statement:**
Before logging attendance, this statement checks whether the user has already logged their time today by calling the hasLoggedToday() function.
* If the user has already logged their time for the day, the function reverts with the message: `"You have already logged time today."`
```
attendanceLog[msg.sender] = Attendance({
name: _name,
userAddress: msg.sender,
timeLoggedAt: block.timestamp
});
```
**Logging Attendance:**
If the user hasn’t logged time today, their attendance is recorded.
* `msg.sender`: The address of the user calling the function.
* `block.timestamp`: The current timestamp, representing the time of the block in which this transaction is included.
This creates an instance of `Attendance` and stores it in the `attendanceLog` mapping using `msg.sender` as the key.
```
function hasLoggedToday() internal view returns (bool) {
```
**Helper Function to Check if the User Has Logged Today:**
The `hasLoggedToday()` function is `internal` and checks whether the user has already logged in today. It is marked as `view` because it doesn’t modify the blockchain state.
Attendance storage userAttendance = attendanceLog[msg.sender];
**Retrieving Attendance Data:**
This retrieves the stored attendance record for the user calling the function (`msg.sender`).
if (userAttendance.timeLoggedAt == 0) {
return false;
}
**Check if the User Has Logged Before:**
If `timeLoggedAt` is zero, it means the user has never logged time before. In this case, the function `returns false`, indicating they haven’t logged today.
uint lastLoggedDay = userAttendance.timeLoggedAt / 1 days;
uint currentDay = block.timestamp / 1 days;
**Calculate Days Since Last Log:**
Here, we calculate both the day the user last logged in and the current day using Unix timestamps divided by 1 days (the number of seconds in a day). This simplifies the timestamp comparison to days instead of seconds.
return lastLoggedDay == currentDay;
**Return Whether the User Has Logged Today:**
This checks if the last time the user logged in falls on the current day. If `lastLoggedDay` equals `currentDay`, the user has already logged today, and the function returns true.