diff --git a/Assignments/Assignment-FRANKHOOD.md/SRegisrty.FRANKHOOD.sol b/Assignments/Assignment-FRANKHOOD.md/SRegisrty.FRANKHOOD.sol new file mode 100644 index 00000000..afea00ee --- /dev/null +++ b/Assignments/Assignment-FRANKHOOD.md/SRegisrty.FRANKHOOD.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +/// @title A Student Registry Contract +/// @author FRANKHOOD +/// @notice This contract registers students with their names, attendance and interests +contract StudentRegistry{ + enum Attendance { + present, + absent + } + + struct Student { + string name; + Attendance attendance; + string[] interests; + } + + mapping(address => Student) public students; + address public owner; + + +/// @param _studentAddress the address of the students that are registered +/// @param _name the name of the students + event StudentCreated(address _studentAddress, string _name); + +/// @param _attendance the attendance of the student address, whether presentor absent + event AttendanceStatus(address _studentAddress, Attendance _attendance); + +/// @param _interest the interests of the students + event InterestAdded(address _studentAddress, string _interest); + event InterestRemoved(address _studentAddress, string _interest); + +/// @param _newName is the new name of the student after changing + event NameUpdated(address _studentAddress, string _newName); + + +/// @notice this modifier requires that only the owner of the contract can perform any function where it is passed + modifier onlyOwner { + require(owner == msg.sender,"you are not the owner"); + _; + } + +/// @notice this modifier requires that the student is registered in any function where it is passed + modifier studentExists(address _address, string memory _name){ + require (bytes(students[_address].name).length > 0, "student is not registered"); + _; + } + +/// @notice this modifier requires that the student is not registered in any function where it is passed + modifier studentDoesNotExist(address _address, string memory _name){ + require (bytes(students[_address].name).length <= 0, "student is already registered"); + _; + } + +/// @notice this function registers students +/// @param _address this is the address of the student +/// @param _name the name of the student +/// @param _attendance the attendance of the student +/// @param _interests the interests of the student + function registerStudent(address _address, string memory _name, Attendance _attendance, string[] memory _interests) public { + students[_address].name = _name; + students[_address].attendance = _attendance; + students[_address].interests = _interests; + + emit StudentCreated(_address, _name); + } + +/// @notice this function registers a new student +/// @dev default Attendance bool is set as false + function registerNewStudent(string memory _name, address _address) public studentDoesNotExist(_address, _name) { + students[_address].name = _name; + students[_address].attendance = Attendance.absent; + + emit StudentCreated(_address, _name); + } + +/// @notice this function marks the attendance of the student + function markAttendance(address _address, string memory _name, Attendance _attendance) public studentExists(_address, _name){ + students[_address].attendance=_attendance; + + emit AttendanceStatus(_address, _attendance); + } + +/// @notice this function adds an interest to the student interests +/// @notice requires the interest to be less than 5 but not empty while ensuring not interest is repeated + function addInterest(address _address, string memory _interest, string memory _name) public studentExists(_address, _name){ + require(bytes(_interest).length > 0, "Interest cannot be empty"); + require(students[_address].interests.length < 5, "Student already has 5 interests"); + + string[] storage interests =students[_address].interests; + + for (uint i = 0; + i < interests.length; + i++){ + require(keccak256(abi.encodePacked(interests[i])) != keccak256(abi.encodePacked(_interest)));// ensuring no interest is repeated + } + + students[_address].interests.push(_interest); + + emit InterestAdded(_address, _interest); + } + +/// @notice this function removes an interest from the arrray +/// @dev to efficiently remove an array, we swap the interest we intend to remove with the last interest of the array + function removeInterest(address _address, string memory _name, string memory _interest) public studentExists(_address, _name){ + string[] storage interests = students[_address].interests; + uint length = interests.length; + + require(length > 0, "No interests to remove"); + + bool found = false; + uint index; + for (uint i = 0; i < length; i++) { + if (keccak256(abi.encodePacked(interests[i])) == keccak256(abi.encodePacked(_interest))) { + found = true; + index = i; + break; + } + } + + require(found, "Interest not found"); + + interests[index] = interests[length - 1];// Replaces the found element with the last element + interests.pop(); // Remove the last element + + emit InterestRemoved(_address, _interest); + } + +/// @notice this function returns the student's name + function getStudentName(address _address, string memory _name) public view studentExists(_address, _name) returns (string memory) { + + return students[_address].name; + } + +/// @notice this function returns the student's attendance + function getStudentAttendance(address _address, string memory _name) public view studentExists(_address, _name) returns (Attendance) { + + return students[_address].attendance; + } + +/// @notice this function returns the student's interests + function getStudentInterests(address _address, string memory _name) public view studentExists(_address, _name) returns (string[] memory interests) { + + return students[_address].interests; + } + + constructor(){ + owner == msg.sender; + } + +/// @notice this function transfers ownership toa new owner + function transferOwnership(address _newOwner) public onlyOwner { + owner = _newOwner; + } + +/// @notice this function updates the student's name to a new name + function updateName(address _address, string memory _name, string memory _newName) public studentExists(_address, _name) { + require(bytes(_newName).length > 0, "Name cannot be empty"); + + students[msg.sender].name = _newName; + + emit NameUpdated(_address, _newName); + } +} \ No newline at end of file diff --git a/Assignments/Assignment-FRANKHOOD.md/assignments b/Assignments/Assignment-FRANKHOOD.md/assignments new file mode 100644 index 00000000..515a26e3 --- /dev/null +++ b/Assignments/Assignment-FRANKHOOD.md/assignments @@ -0,0 +1,13 @@ +# Assignment 1 + +Here's a link to [Assignment 1](../Assignment-1.md/counter..FRANKHOOD.sol) + +The Assignment creates a simple Counter contract that increases by one, by value and decreases by one, by value + +# Assignment 2 + +Here's the link to [Assignment 2](../Assignment-FRANKHOOD.md/counter..FRANKHOOD.sol) + +This Student Registry contract registers students taking into account their name, attendance and interests +the contracts allows students to remove interests, add interests, and update their name +it successfully compiled in hardhat diff --git a/Assignments/Assignment-FRANKHOOD.md/counter..FRANKHOOD.sol b/Assignments/Assignment-FRANKHOOD.md/counter..FRANKHOOD.sol new file mode 100644 index 00000000..01907118 --- /dev/null +++ b/Assignments/Assignment-FRANKHOOD.md/counter..FRANKHOOD.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +/// @title Counter Contract Implementation +/// @author FRANKHOOD +/// @notice this contract defines the count and maximum value of the count +/// @dev All function calls are currently implemented without side effects +contract Counter{ + uint public count = 0; + uint maxValue = getMaxUint256 (); + +/// @notice this event is emitted when the count is increased +/// @param amount the value of the count after increasing +/// @param timestamp the time the count increased +event CountIncreased(uint amount, uint timestamp); + +/// @notice this event is emitted when the count is decreased +/// @param amount the value of the count after decreasing +/// @param timestamp the time the count decreased +event CountDecreased(uint amount, uint timestamp); + +/// @notice this function increases the count by 0ne +/// @notice this function is reverted if it exceeds the maxValue +function increaseByOne() public { + require(count < maxValue, "cannot increase beyond max uint"); + count ++; + emit CountIncreased(count, block.timestamp); +} + +/// @notice this function increases the count by a value that must be greater than 0 +/// @notice this function is reverted if it exceeds the maxValue +function increaseByValue(uint _value) public { + require (_value > 0); + require(count < maxValue, "cannot increase beyond max uint"); + count += _value; + emit CountIncreased(count, block.timestamp); +} + +/// @notice this function decreases the count by 0ne +/// @notice this function is reverted if the value of count is less than 1 +function decreaseByOne() public { + require(count >= 1,"cannot decrease below 0"); + count --; + emit CountDecreased(count, block.timestamp); +} + +/// @notice this function decreases the count by a value greater than or equal to one +/// @notice this function is reverted if the result is greater than maxValue +function decreaseByValue(uint _value) public { + require(count >= 1,"cannot decrease below 0"); + require(count + _value <= maxValue); + count += _value; + emit CountDecreased(count, block.timestamp); +} + +/// @notice this function resets the count to original value - 0 +function resetCount() public { + count = 0; + emit CountDecreased(count, block.timestamp); +} + +/// @notice this function returns the current value of count +function getCount() public view returns (uint){ + return count; +} + +/// @notice this function returns the maximum value of count +function getMaxUint256() public pure returns (uint){ + unchecked { + return uint256 (0)-1; + } +} +} \ No newline at end of file diff --git a/contracts/counter.frankhood.sol b/contracts/counter.frankhood.sol new file mode 100644 index 00000000..01907118 --- /dev/null +++ b/contracts/counter.frankhood.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +/// @title Counter Contract Implementation +/// @author FRANKHOOD +/// @notice this contract defines the count and maximum value of the count +/// @dev All function calls are currently implemented without side effects +contract Counter{ + uint public count = 0; + uint maxValue = getMaxUint256 (); + +/// @notice this event is emitted when the count is increased +/// @param amount the value of the count after increasing +/// @param timestamp the time the count increased +event CountIncreased(uint amount, uint timestamp); + +/// @notice this event is emitted when the count is decreased +/// @param amount the value of the count after decreasing +/// @param timestamp the time the count decreased +event CountDecreased(uint amount, uint timestamp); + +/// @notice this function increases the count by 0ne +/// @notice this function is reverted if it exceeds the maxValue +function increaseByOne() public { + require(count < maxValue, "cannot increase beyond max uint"); + count ++; + emit CountIncreased(count, block.timestamp); +} + +/// @notice this function increases the count by a value that must be greater than 0 +/// @notice this function is reverted if it exceeds the maxValue +function increaseByValue(uint _value) public { + require (_value > 0); + require(count < maxValue, "cannot increase beyond max uint"); + count += _value; + emit CountIncreased(count, block.timestamp); +} + +/// @notice this function decreases the count by 0ne +/// @notice this function is reverted if the value of count is less than 1 +function decreaseByOne() public { + require(count >= 1,"cannot decrease below 0"); + count --; + emit CountDecreased(count, block.timestamp); +} + +/// @notice this function decreases the count by a value greater than or equal to one +/// @notice this function is reverted if the result is greater than maxValue +function decreaseByValue(uint _value) public { + require(count >= 1,"cannot decrease below 0"); + require(count + _value <= maxValue); + count += _value; + emit CountDecreased(count, block.timestamp); +} + +/// @notice this function resets the count to original value - 0 +function resetCount() public { + count = 0; + emit CountDecreased(count, block.timestamp); +} + +/// @notice this function returns the current value of count +function getCount() public view returns (uint){ + return count; +} + +/// @notice this function returns the maximum value of count +function getMaxUint256() public pure returns (uint){ + unchecked { + return uint256 (0)-1; + } +} +} \ No newline at end of file