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/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 4f5bb554..24675b67 100644 --- a/contracts/StudentRegistry.sol +++ b/contracts/StudentRegistry.sol @@ -1,51 +1,125 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import "./Ownable.sol"; +import "./Student.sol"; -contract StudentRegistry { - //custom data type - struct Student { - address studentAddr; - string name; - uint256 studentId; - uint8 age; - } - address public owner; +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; - + 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 isOfAge(uint8 _age) { + if (_age < 18) { + revert UnderAge(_age, 18); + } _; } - modifier isNotAddressZero () { - require(msg.sender != address(0), "Invalid Address"); + 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].hasPaid, + "Duplicate Registration" + ); + studentsMapping[_studentAddr] = studentsPool[_studentAddr]; + + emit Registration(_studentAddr, "Enlisted Successfully"); + return true; + } + + function addStudent( address _studentAddr, string memory _name, uint8 _age - ) public onlyOwner isNotAddressZero { + ) public isNotAddressZero { + if (bytes(_name).length == 0) { + revert NameIsEmpty(); + } - require( bytes(_name).length > 0, "Name cannot be blank"); - require( _age >= 18, "This student is under age"); + 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); @@ -53,26 +127,34 @@ contract StudentRegistry { studentsMapping[_studentAddr] = 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) public - isNotAddressZero view + isNotAddressZero 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 + { + require( + studentsMapping[_studentAddr].studentAddr != address(0), + "Student does not exist" + ); // delete studentsMapping[_studentAddr]; @@ -80,10 +162,31 @@ contract StudentRegistry { studentAddr: address(0), name: "", age: 0, - studentId: 0 + studentId: 0, + hasPaid: true }); studentsMapping[_studentAddr] = 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; } }