From 13f7f9ea1c65f0da241c36ef2835e61d493694db Mon Sep 17 00:00:00 2001 From: Favour onyinye Date: Mon, 29 Jul 2024 01:55:33 -1100 Subject: [PATCH 1/2] chore: My assignment --- .vscode/settings.json | 2 +- contracts/StudentRegistry.sol | 93 ++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bc1c7197..81a53ff8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "solidity.compileUsingRemoteVersion": "v0.8.14+commit.80d49f37" + "solidity.compileUsingRemoteVersion": "v0.8.24+commit.80d49f37" } \ No newline at end of file diff --git a/contracts/StudentRegistry.sol b/contracts/StudentRegistry.sol index 4f5bb554..fcb0601c 100644 --- a/contracts/StudentRegistry.sol +++ b/contracts/StudentRegistry.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; + contract StudentRegistry { - //custom data type + struct Student { address studentAddr; string name; @@ -10,35 +11,53 @@ contract StudentRegistry { uint8 age; } - address public owner; - constructor() { owner = msg.sender; } - //dynamic array of students + Student[] private students; - + address public owner; mapping(address => Student) public studentsMapping; - modifier onlyOwner () { - require( owner == msg.sender, "You fraud!!!"); + + modifier onlyOwner() { + require(owner == msg.sender, "You fraud!!!"); _; } - modifier isNotAddressZero () { + modifier isNotAddressZero() { require(msg.sender != address(0), "Invalid Address"); _; } + modifier isAdult(uint8 _age) { + require(_age >= 18, "You're under age."); + _; + } + + modifier isValidAge(uint8 _age) { + require(_age <= 255, "Cannot exceed max limit(255)"); + _; + } + + modifier isRegistered(address _studentAddr) { + require( + studentsMapping[_studentAddr].studentAddr != address(0), + "Student not found." + ); + _; + } + + event StudentEvent(string message, Student student); + function addStudent( address _studentAddr, string memory _name, uint8 _age - ) public onlyOwner isNotAddressZero { - - require( bytes(_name).length > 0, "Name cannot be blank"); - require( _age >= 18, "This student is under age"); + ) public onlyOwner isNotAddressZero isAdult(_age) isValidAge(_age) { + require(bytes(_name).length > 0, "Name cannot be blank"); + require(_age >= 18, "This student is under age"); uint256 _studentId = students.length + 1; Student memory student = Student({ @@ -51,29 +70,33 @@ contract StudentRegistry { students.push(student); // add student to studentsMapping studentsMapping[_studentAddr] = student; + emit StudentEvent("Student registered successfully.", student); } - function getStudent(uint8 _studentId) public isNotAddressZero view returns (Student memory) { + + function getStudent( + uint8 _studentId + ) public view isNotAddressZero returns (Student memory) { return students[_studentId - 1]; } - - - function getStudentFromMapping(address _studentAddr) + + function getStudentFromMapping( + address _studentAddr + ) public - isNotAddressZero view + isNotAddressZero + isRegistered(_studentAddr) returns (Student memory) { return studentsMapping[_studentAddr]; } - - - function deleteStudent(address _studentAddr) public onlyOwner isNotAddressZero{ - - require(studentsMapping[_studentAddr].studentAddr != address(0), "Student does not exist"); - + + function deleteStudent( + address _studentAddr + ) public onlyOwner isNotAddressZero isRegistered(_studentAddr) { // delete studentsMapping[_studentAddr]; Student memory student = Student({ @@ -84,6 +107,28 @@ contract StudentRegistry { }); studentsMapping[_studentAddr] = student; + } + + function updateStudent( + address _studentAddr, + string memory _name, + uint8 _age + ) + public + onlyOwner + isNotAddressZero + isRegistered(_studentAddr) + isAdult(_age) + isValidAge(_age) + { + Student memory student = studentsMapping[_studentAddr]; + + if (bytes(_name).length > 0) { + student.name = _name; + } + student.age = _age; + studentsMapping[_studentAddr] = student; + emit StudentEvent("Student record updated.", student); } -} +} \ No newline at end of file From 7eba6100a910ee04196e60703bd7b03b6057b7ef Mon Sep 17 00:00:00 2001 From: Favour onyinye Date: Fri, 9 Aug 2024 22:49:12 -1100 Subject: [PATCH 2/2] Student Registration --- contracts/IStudentRegistry.sol | 39 +++++++ contracts/MyStudentRegistry.sol | 38 +++++++ contracts/Ownable.sol | 33 ++++++ contracts/Student.sol | 9 ++ contracts/StudentRegistry.sol | 190 +++++++++++++++++++++----------- 5 files changed, 243 insertions(+), 66 deletions(-) create mode 100644 contracts/IStudentRegistry.sol create mode 100644 contracts/MyStudentRegistry.sol create mode 100644 contracts/Ownable.sol create mode 100644 contracts/Student.sol diff --git a/contracts/IStudentRegistry.sol b/contracts/IStudentRegistry.sol new file mode 100644 index 00000000..ebcd87b1 --- /dev/null +++ b/contracts/IStudentRegistry.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; +import "./Student.sol"; +interface IStudentRegistry { + + + function addStudent( + address _studentAddr, + string memory _name, + uint8 _age + ) external; + + function getStudent(uint8 _studentID) external view returns (Student memory); + + function getStudentFromMapping(address _studentAddr) external view returns (Student memory); + + function registerStudent( + address _studentAddr, + uint8 _age, + string memory _name + ) external payable returns (bool); + + function authorizeStudentRegistration( + address _studentAddr + ) external returns (bool); + + function updateStudent( + address _studentAddr, + uint8 _age, + string memory _name + ) external returns (Student memory); + + function withdraw() external returns (bool); + + function getBalance() external view returns (uint256); + + function deleteStudent(address _studentAddr) external; + +} diff --git a/contracts/MyStudentRegistry.sol b/contracts/MyStudentRegistry.sol new file mode 100644 index 00000000..943523cf --- /dev/null +++ b/contracts/MyStudentRegistry.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.7.0 <0.9.0; +import "./IStudentRegistry.sol"; +import "./Student.sol"; +import "./Ownable.sol"; + + +// Pay 1 Eth to register a student +// Collect student's name, age, address +// Admin should add registered students to the Registry +// Check if the students has paid.(hasPaid => Student) +// + +contract MyStudentRegistry is Ownable { + + address private StudentRegistryContractAddress; + + constructor(address _studentRgistry){ + StudentRegistryContractAddress = _studentRgistry; + } + + function registerStudent( + address _studentAddr, + string memory _name, + uint8 _age + ) public onlyOwner { + + IStudentRegistry(StudentRegistryContractAddress).addStudent(_studentAddr, _name, _age); + } + + + function getStudent2( + uint8 _studentId + ) public view returns (Student memory) { + + return IStudentRegistry(StudentRegistryContractAddress).getStudent(_studentId); + } +} \ No newline at end of file diff --git a/contracts/Ownable.sol b/contracts/Ownable.sol new file mode 100644 index 00000000..8f8df4fe --- /dev/null +++ b/contracts/Ownable.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.7.0 <0.9.0; + + +contract Ownable { + + address payable private owner; + + event ChangeOwner(address indexed oldOwner, address indexed newOwner); + + constructor(){ + owner = payable (msg.sender); + } + + + modifier onlyOwner { + require(owner == msg.sender, "Caller not owner"); + _; + } + + + function getOwner() public view returns (address){ + return owner; + } + + + function changeOwner(address payable _newOwner) internal onlyOwner { + require(_newOwner != address(0), "Owner can not be address zero"); + + emit ChangeOwner(owner, _newOwner); + owner = _newOwner; + } +} \ No newline at end of file diff --git a/contracts/Student.sol b/contracts/Student.sol new file mode 100644 index 00000000..89b69c83 --- /dev/null +++ b/contracts/Student.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + struct Student { + address studentAddr; + string name; + uint256 studentId; + uint8 age; + bool hasPaid; + } diff --git a/contracts/StudentRegistry.sol b/contracts/StudentRegistry.sol index fcb0601c..24675b67 100644 --- a/contracts/StudentRegistry.sol +++ b/contracts/StudentRegistry.sol @@ -1,134 +1,192 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import "./Ownable.sol"; +import "./Student.sol"; -contract StudentRegistry { - - struct Student { - address studentAddr; - string name; - uint256 studentId; - uint8 age; - } +contract StudentRegistry is Ownable { + //custom erros + error NameIsEmpty(); + error NotRegistered(); + error UnderAge(uint8 age, uint8 expectedAge); - constructor() { - owner = msg.sender; - } + //Event Registration + event Registration(address indexed _studentAddress, string _message); + + //dynamic array of students Student[] private students; - address public owner; + uint256 private studentsCount; + mapping(address => Student) private studentsPool; mapping(address => Student) public studentsMapping; - - modifier onlyOwner() { - require(owner == msg.sender, "You fraud!!!"); - _; - } modifier isNotAddressZero() { require(msg.sender != address(0), "Invalid Address"); _; } - - modifier isAdult(uint8 _age) { - require(_age >= 18, "You're under age."); + modifier isOfAge(uint8 _age) { + if (_age < 18) { + revert UnderAge(_age, 18); + } _; } - modifier isValidAge(uint8 _age) { - require(_age <= 255, "Cannot exceed max limit(255)"); + modifier isValidName(string memory _name) { + if (bytes(_name).length <= 0) { + revert NameIsEmpty(); + } _; } modifier isRegistered(address _studentAddr) { + if (!studentsPool[_studentAddr].hasPaid) { + revert NotRegistered(); + } + _; + } + + + +// RegisterStudent + function registerStudent( + address _studentAddr, + uint8 _age, + string memory _name + ) + public + payable + isNotAddressZero + isOfAge(_age) + isValidName(_name) + returns (bool) + { + require(!studentsPool[_studentAddr].hasPaid, "Duplicate Registration"); + uint256 regFee = msg.value; + require(regFee == 1 ether, "Registration Fee is 1Eth"); + + studentsCount += 1; + studentsPool[_studentAddr] = Student({ + studentAddr: _studentAddr, + name: _name, + age: _age, + studentId: studentsCount, + hasPaid: true + }); + + emit Registration(_studentAddr, "Registration Successful"); + return true; + } + +// authorizeStudentRegistration + function authorizeStudentRegistration( + address _studentAddr + ) + public + isNotAddressZero + onlyOwner + isRegistered(_studentAddr) + returns (bool) + { require( - studentsMapping[_studentAddr].studentAddr != address(0), - "Student not found." + !studentsMapping[_studentAddr].hasPaid, + "Duplicate Registration" ); - _; + studentsMapping[_studentAddr] = studentsPool[_studentAddr]; + + emit Registration(_studentAddr, "Enlisted Successfully"); + return true; } - event StudentEvent(string message, Student student); function addStudent( address _studentAddr, string memory _name, uint8 _age - ) public onlyOwner isNotAddressZero isAdult(_age) isValidAge(_age) { - require(bytes(_name).length > 0, "Name cannot be blank"); - require(_age >= 18, "This student is under age"); + ) public isNotAddressZero { + if (bytes(_name).length == 0) { + revert NameIsEmpty(); + } + + if (_age < 18) { + revert UnderAge({age: _age, expectedAge: 18}); + } uint256 _studentId = students.length + 1; Student memory student = Student({ studentAddr: _studentAddr, name: _name, age: _age, - studentId: _studentId + studentId: _studentId, + hasPaid: true }); students.push(student); // add student to studentsMapping studentsMapping[_studentAddr] = student; - emit StudentEvent("Student registered successfully.", student); } - - function getStudent( - uint8 _studentId - ) public view isNotAddressZero returns (Student memory) { + function getStudent(uint8 _studentId) + public + view + isNotAddressZero + returns (Student memory) + { return students[_studentId - 1]; } - - function getStudentFromMapping( - address _studentAddr - ) + + function getStudentFromMapping(address _studentAddr) public view isNotAddressZero - isRegistered(_studentAddr) returns (Student memory) { return studentsMapping[_studentAddr]; } - - function deleteStudent( - address _studentAddr - ) public onlyOwner isNotAddressZero isRegistered(_studentAddr) { + function deleteStudent(address _studentAddr) + public + onlyOwner + isNotAddressZero + { + require( + studentsMapping[_studentAddr].studentAddr != address(0), + "Student does not exist" + ); + // delete studentsMapping[_studentAddr]; Student memory student = Student({ studentAddr: address(0), name: "", age: 0, - studentId: 0 + studentId: 0, + hasPaid: true }); studentsMapping[_studentAddr] = student; } - - function updateStudent( - address _studentAddr, - string memory _name, - uint8 _age - ) - public - onlyOwner - isNotAddressZero - isRegistered(_studentAddr) - isAdult(_age) - isValidAge(_age) - { - Student memory student = studentsMapping[_studentAddr]; - if (bytes(_name).length > 0) { - student.name = _name; - } - student.age = _age; - studentsMapping[_studentAddr] = student; - emit StudentEvent("Student record updated.", student); + function modifyOwner(address payable _newOwner) public { + changeOwner(_newOwner); + } + + // Withdraw + function withdraw() public isNotAddressZero onlyOwner returns (bool) { + uint256 balance = address(this).balance; + require(balance > 0, "Empty Balance"); + + (bool withdrawn, ) = payable(getOwner()).call{value: balance}(""); + require(withdrawn, "Withdrawal failed"); + + return withdrawn; + } + + // Getting the current balance + function getBalance() public view returns (uint256) { + return address(this).balance; } -} \ No newline at end of file +}