From fc6757a4498346b7647a06d1a3086a87f2b74e03 Mon Sep 17 00:00:00 2001 From: frankhood Date: Fri, 14 Feb 2025 17:15:03 +0100 Subject: [PATCH 1/4] add counter contract --- contracts/counter.frankhood.sol | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 contracts/counter.frankhood.sol diff --git a/contracts/counter.frankhood.sol b/contracts/counter.frankhood.sol new file mode 100644 index 00000000..e69de29b From 19c81c70feb26088f5c30f1ace27087a42927286 Mon Sep 17 00:00:00 2001 From: frankhood Date: Wed, 19 Feb 2025 14:29:07 +0100 Subject: [PATCH 2/4] chore: add counter contract --- Assignments/Assignment-1.md/assignment1 | 4 + .../Assignment-1.md/counter..FRANKHOOD.sol | 73 +++++++++++++++++++ contracts/counter.frankhood.sol | 73 +++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 Assignments/Assignment-1.md/assignment1 create mode 100644 Assignments/Assignment-1.md/counter..FRANKHOOD.sol diff --git a/Assignments/Assignment-1.md/assignment1 b/Assignments/Assignment-1.md/assignment1 new file mode 100644 index 00000000..4493485b --- /dev/null +++ b/Assignments/Assignment-1.md/assignment1 @@ -0,0 +1,4 @@ +# Assignment 1 + +Here's a link to [Assignment 1](../../contracts/counter.frankhood.sol) + diff --git a/Assignments/Assignment-1.md/counter..FRANKHOOD.sol b/Assignments/Assignment-1.md/counter..FRANKHOOD.sol new file mode 100644 index 00000000..01907118 --- /dev/null +++ b/Assignments/Assignment-1.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 index e69de29b..01907118 100644 --- a/contracts/counter.frankhood.sol +++ 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 From 68e43223996a3d042928c8dcdc37daa590ba191c Mon Sep 17 00:00:00 2001 From: frankhood Date: Sun, 23 Feb 2025 06:41:28 +0100 Subject: [PATCH 3/4] feat: Create a Student Registry --- Assignments/Assignment-1.md/assignment1 | 4 - .../SRegisrty.FRANKHOOD.sol | 165 ++++++++++++++++++ .../Assignment-FRANKHOOD.md/assignments | 13 ++ .../counter..FRANKHOOD.sol | 0 Assignments/CrowdFunding.FRANKHOOD/ERC20.sol | 64 +++++++ Assignments/CrowdFunding.FRANKHOOD/ERC721.sol | 77 ++++++++ .../CrowdFunding.FRANKHOOD/IERC721.sol | 13 ++ .../CrowdFunding.FRANKHOOD/crowdFunding.sol | 108 ++++++++++++ 8 files changed, 440 insertions(+), 4 deletions(-) delete mode 100644 Assignments/Assignment-1.md/assignment1 create mode 100644 Assignments/Assignment-FRANKHOOD.md/SRegisrty.FRANKHOOD.sol create mode 100644 Assignments/Assignment-FRANKHOOD.md/assignments rename Assignments/{Assignment-1.md => Assignment-FRANKHOOD.md}/counter..FRANKHOOD.sol (100%) create mode 100644 Assignments/CrowdFunding.FRANKHOOD/ERC20.sol create mode 100644 Assignments/CrowdFunding.FRANKHOOD/ERC721.sol create mode 100644 Assignments/CrowdFunding.FRANKHOOD/IERC721.sol create mode 100644 Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol diff --git a/Assignments/Assignment-1.md/assignment1 b/Assignments/Assignment-1.md/assignment1 deleted file mode 100644 index 4493485b..00000000 --- a/Assignments/Assignment-1.md/assignment1 +++ /dev/null @@ -1,4 +0,0 @@ -# Assignment 1 - -Here's a link to [Assignment 1](../../contracts/counter.frankhood.sol) - 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-1.md/counter..FRANKHOOD.sol b/Assignments/Assignment-FRANKHOOD.md/counter..FRANKHOOD.sol similarity index 100% rename from Assignments/Assignment-1.md/counter..FRANKHOOD.sol rename to Assignments/Assignment-FRANKHOOD.md/counter..FRANKHOOD.sol diff --git a/Assignments/CrowdFunding.FRANKHOOD/ERC20.sol b/Assignments/CrowdFunding.FRANKHOOD/ERC20.sol new file mode 100644 index 00000000..209bcbf0 --- /dev/null +++ b/Assignments/CrowdFunding.FRANKHOOD/ERC20.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.26; + +contract ERC20 { + string public name; + string public symbol; + uint8 public decimals; + uint256 public totalSupply; + + mapping (address => uint256) public balanceOf; + mapping (address => mapping(address => uint256)) public allowance; + + event Transfer (address indexed from, address indexed to, uint256 value); + event Approval (address indexed owner, address indexed spender, uint value); + + constructor(string memory _name, string memory _symbol, uint8 _decimals) { + name = _name; + symbol = _symbol; + decimals = _decimals; + } + + + function transfer(address recipient, uint256 amount) external returns (bool) { + require(balanceOf[msg.sender] >= amount); + balanceOf[msg.sender] -= amount; + balanceOf[recipient] += amount; + + emit Transfer(msg.sender, recipient, amount); + return true; + } + + function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { + allowance[sender][msg.sender] -= amount; + balanceOf[sender] -= amount; + balanceOf[recipient] += amount; + emit Transfer(sender, recipient, amount); + return true; + } + + function _mint (address _to, uint256 _amount) virtual public { + require(msg.sender != address(0), "zero address"); + balanceOf[_to] += _amount; + totalSupply += _amount; + + emit Transfer(address(0), _to, _amount); + } + + function _burn (address, uint256 _amount) public { + require(balanceOf[msg.sender] >= _amount, "insufficient funds"); + totalSupply -= _amount; + balanceOf[msg.sender] -= _amount; + balanceOf[address(0)] -= _amount; + + emit Transfer(msg.sender, address(0), _amount); + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function burn(address from, uint256 amount) external { + _burn(from, amount); + } +} \ No newline at end of file diff --git a/Assignments/CrowdFunding.FRANKHOOD/ERC721.sol b/Assignments/CrowdFunding.FRANKHOOD/ERC721.sol new file mode 100644 index 00000000..888986ab --- /dev/null +++ b/Assignments/CrowdFunding.FRANKHOOD/ERC721.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier:MIT +pragma solidity ^0.8.24; + +import "./IERC721.sol"; + +contract ERC721 is IERC721 { + // Mapping fron tokenId to owner address + mapping (uint256=> address) internal _ownerOf; + + //Mapping from owner address to token count + mapping (address => uint256) internal _balanceOf; + + //Mapping from tokenId to approved address + mapping (uint256 => address) internal _approvals; + + //Mapping from owner to operator approvals + mapping (address => mapping (address => bool)) public isApprovedForAll; + + event NFTTransfer(address indexed from, address indexed to, uint256 indexed id); + event NFTApproval(address indexed owner, address indexed spender, uint256 indexed id); + event ApprovalForAll(address indexed owner, address operator, bool approved); + + function nftBalanceOf(address owner) external view returns (uint256) { + require(owner != address(0), "owner = zero address"); + return _balanceOf[owner]; + } + + function ownerOf(uint256 tokenId) external view returns (address ownerOfToken) { + ownerOfToken = _ownerOf[tokenId]; + require(ownerOfToken != address(0), "token doesn't exist"); + } + + function setApprovalForAll(address operator, bool approved) external { + isApprovedForAll[msg.sender][operator] = approved; + emit ApprovalForAll(msg.sender,operator,approved); + } + + function approve(address to, uint256 tokenId) external { + address owner = _ownerOf[tokenId]; + require(msg.sender == owner || isApprovedForAll[owner][msg.sender], 'not authorised'); + + _approvals[tokenId] = to; + + emit NFTApproval(owner, to, tokenId); + } + + function getApproved(uint256 tokenId) external view returns (address) { + require (_ownerOf[tokenId] !=address(0), "token does not exist"); + return _approvals[tokenId]; + } + + function isApprovedOrOwner(address owner, address spender, uint256 id) private view returns (bool) { + return (spender == owner || isApprovedForAll[owner][spender] || spender == _approvals[id]); + } + + function nftTransferFrom(address from, address to, uint256 tokenId) external { + require(from == _ownerOf[tokenId], "from != owner"); + require(to != address(0), "transfer to zero address"); + require(isApprovedOrOwner(from, msg.sender, tokenId), "not authorised"); + + _balanceOf[from]--; + _balanceOf[to]++; + _ownerOf[tokenId] = to; + + delete _approvals[tokenId]; + } + + function _mintNFT(address to, uint256 tokenId) internal virtual { + require(to != address(0), "mint to zero address"); + require(_ownerOf[tokenId] == address(0), "already minted"); + + _balanceOf[to]++; + _ownerOf[tokenId] = to; + + emit NFTTransfer(address(0), to, tokenId); + } +} diff --git a/Assignments/CrowdFunding.FRANKHOOD/IERC721.sol b/Assignments/CrowdFunding.FRANKHOOD/IERC721.sol new file mode 100644 index 00000000..b06572bf --- /dev/null +++ b/Assignments/CrowdFunding.FRANKHOOD/IERC721.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier:MIT +pragma solidity ^0.8.24; + +interface IERC721 { + function nftBalanceOf(address owner) external view returns (uint256 balance); + function ownerOf(uint tokenId) external view returns (address owner); + //function safeTransferFrom(address from, address to, uint tokenId, bytes memory data) external; + //function safeTransferFrom(address from, address to, uint tokenId) external; + function nftTransferFrom(address from, address to, uint tokenId) external; + function approve(address to, uint256 tokenId) external; + function setApprovalForAll(address operator, bool approved) external; + function isApprovedForAll(address owner, address operator) external view returns (bool); +} \ No newline at end of file diff --git a/Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol b/Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol new file mode 100644 index 00000000..8af9db35 --- /dev/null +++ b/Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.28; + +import "./ERC20.sol"; +import "./ERC721.sol"; + +/// @title A CrowdFunding Contract +/// @author FRANKHOOD +/// @notice this contract ERC20 and ERC721 tokens from the crowdFunding folder +abstract contract CrowdFund is ERC20, ERC721{ + uint public amount; + uint public _threshhold; + address private crowdFund; + bool TokenClaimed; + bool NFTClaimed; + +/// @notice funder and alreadyClaimed are the addresses that interact with the contract +/// @dev these addresse hold the ERC20 and ERC721 tokens + mapping (address => uint) funder; + mapping (address => uint) alreadyClaimed; + +/// @param _from is the address that calls this function by adding ERC20 to the crowFund +/// @param _amount is the amount of ERC20 added by the _from address + event ContributionMade(address indexed _from, uint _amount); + event TreshholdExceeded(address indexed _from, uint _amount); + +/// @param _to is the address that calls this function by adding ERC20 to the crowFund + event TokenWithdrawn(address indexed _to, uint _amount); + event RewardReceived(address indexed _to, uint _amount); + + +/// @notice this function is payable so it receives the ERC20 tokens +/// @param _from is the address that calls this function by adding ERC20 to the crowFund +/// @param _amount is the amount of ERC20 added by the _from address + function contribution(address _from, uint _amount) payable public { + require(_amount > 0,"Contribution cannot be 0"); + balanceOf[crowdFund] += _amount; + balanceOf[_from] -= _amount; + + funder[_from] += _amount; + TokenClaimed = false;//this argument says that the address has not received reward tokens yet + + emit ContributionMade(_from, _amount); + } + + +/// @notice this function requires the address to contribute an amount greater than 0 to the crowdFund before executing +/// @notice the receiving address cannot be address(0) +/// @notice the tokenClaimed boolean returns as true after the function executes +/// @param _to is the address that calls this function by adding ERC20 to the crowFund +/// @param _amount is the amount of ERC20 added by the _from address + function _mint (address _to, uint256 _amount) virtual override public { + require(TokenClaimed = false, "already claimed reward"); + require(alreadyClaimed[_to] == funder[_to]); + require(funder[_to] > 0,"amount must be greater than 0"); + require(msg.sender != address(0), "zero address"); + balanceOf[_to] += _amount; + totalSupply += _amount; + + TokenClaimed = true;//returns TokenClaimed boolean as true after execuion + + emit Transfer(address(0), _to, _amount); + emit RewardReceived(_to, amount); + } + +/// @notice this function sets the _threshhold at 10 ether and a requirement for execution + function threshhold(address _from, uint _amount) public returns (uint) { + require(_amount >= 10 ether, "not up to 10 ether"); + _threshhold = _amount; + + balanceOf[crowdFund] += _threshhold; + balanceOf[_from] -= _threshhold; + + funder[_from] += _threshhold; + + emit TreshholdExceeded(_from, _amount); + + return _threshhold; + } + + +/// @notice this function does not mint to address 0 and prevents double minting by returning NFTclaimed boolean as true after execuion +/// @param tokenId is the NFT minted when an address reaches the threshhold + function _mintNFT(address _to, uint256 tokenId) internal override { + require(_to != address(0), "mint to zero address"); + require(_ownerOf[tokenId] == address(0), "already minted"); + require(NFTClaimed = false,"Already Claimed"); + require(funder[_to] >= _threshhold); + _balanceOf[_to]++; + _ownerOf[tokenId] = _to; + + NFTClaimed = true;//returns NFTclaimed boolean as true after execuion + + emit Transfer(address(0), _to, tokenId); + emit RewardReceived(_to, amount); + } + + +/// @notice this function enables the user to withdraw their contribution +/// @notice this function requires the amount withdrawable to be less than their contribution + function withrawal(address _to, uint _amount) public { + require(funder[_to] <= funder[_to], "amount withdrawable cannot exceed amount comitted"); + balanceOf[crowdFund] -= _amount; + balanceOf[_to] += _amount; + + emit TokenWithdrawn(_to, _amount); + } +} \ No newline at end of file From 0c597dfb5e788bf10ed4191e9d30364c8ab35bf9 Mon Sep 17 00:00:00 2001 From: frankhood Date: Sun, 23 Feb 2025 06:46:13 +0100 Subject: [PATCH 4/4] feat: add Student Registry --- Assignments/CrowdFunding.FRANKHOOD/ERC20.sol | 64 ----------- Assignments/CrowdFunding.FRANKHOOD/ERC721.sol | 77 ------------- .../CrowdFunding.FRANKHOOD/IERC721.sol | 13 --- .../CrowdFunding.FRANKHOOD/crowdFunding.sol | 108 ------------------ 4 files changed, 262 deletions(-) delete mode 100644 Assignments/CrowdFunding.FRANKHOOD/ERC20.sol delete mode 100644 Assignments/CrowdFunding.FRANKHOOD/ERC721.sol delete mode 100644 Assignments/CrowdFunding.FRANKHOOD/IERC721.sol delete mode 100644 Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol diff --git a/Assignments/CrowdFunding.FRANKHOOD/ERC20.sol b/Assignments/CrowdFunding.FRANKHOOD/ERC20.sol deleted file mode 100644 index 209bcbf0..00000000 --- a/Assignments/CrowdFunding.FRANKHOOD/ERC20.sol +++ /dev/null @@ -1,64 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.26; - -contract ERC20 { - string public name; - string public symbol; - uint8 public decimals; - uint256 public totalSupply; - - mapping (address => uint256) public balanceOf; - mapping (address => mapping(address => uint256)) public allowance; - - event Transfer (address indexed from, address indexed to, uint256 value); - event Approval (address indexed owner, address indexed spender, uint value); - - constructor(string memory _name, string memory _symbol, uint8 _decimals) { - name = _name; - symbol = _symbol; - decimals = _decimals; - } - - - function transfer(address recipient, uint256 amount) external returns (bool) { - require(balanceOf[msg.sender] >= amount); - balanceOf[msg.sender] -= amount; - balanceOf[recipient] += amount; - - emit Transfer(msg.sender, recipient, amount); - return true; - } - - function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { - allowance[sender][msg.sender] -= amount; - balanceOf[sender] -= amount; - balanceOf[recipient] += amount; - emit Transfer(sender, recipient, amount); - return true; - } - - function _mint (address _to, uint256 _amount) virtual public { - require(msg.sender != address(0), "zero address"); - balanceOf[_to] += _amount; - totalSupply += _amount; - - emit Transfer(address(0), _to, _amount); - } - - function _burn (address, uint256 _amount) public { - require(balanceOf[msg.sender] >= _amount, "insufficient funds"); - totalSupply -= _amount; - balanceOf[msg.sender] -= _amount; - balanceOf[address(0)] -= _amount; - - emit Transfer(msg.sender, address(0), _amount); - } - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } - - function burn(address from, uint256 amount) external { - _burn(from, amount); - } -} \ No newline at end of file diff --git a/Assignments/CrowdFunding.FRANKHOOD/ERC721.sol b/Assignments/CrowdFunding.FRANKHOOD/ERC721.sol deleted file mode 100644 index 888986ab..00000000 --- a/Assignments/CrowdFunding.FRANKHOOD/ERC721.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier:MIT -pragma solidity ^0.8.24; - -import "./IERC721.sol"; - -contract ERC721 is IERC721 { - // Mapping fron tokenId to owner address - mapping (uint256=> address) internal _ownerOf; - - //Mapping from owner address to token count - mapping (address => uint256) internal _balanceOf; - - //Mapping from tokenId to approved address - mapping (uint256 => address) internal _approvals; - - //Mapping from owner to operator approvals - mapping (address => mapping (address => bool)) public isApprovedForAll; - - event NFTTransfer(address indexed from, address indexed to, uint256 indexed id); - event NFTApproval(address indexed owner, address indexed spender, uint256 indexed id); - event ApprovalForAll(address indexed owner, address operator, bool approved); - - function nftBalanceOf(address owner) external view returns (uint256) { - require(owner != address(0), "owner = zero address"); - return _balanceOf[owner]; - } - - function ownerOf(uint256 tokenId) external view returns (address ownerOfToken) { - ownerOfToken = _ownerOf[tokenId]; - require(ownerOfToken != address(0), "token doesn't exist"); - } - - function setApprovalForAll(address operator, bool approved) external { - isApprovedForAll[msg.sender][operator] = approved; - emit ApprovalForAll(msg.sender,operator,approved); - } - - function approve(address to, uint256 tokenId) external { - address owner = _ownerOf[tokenId]; - require(msg.sender == owner || isApprovedForAll[owner][msg.sender], 'not authorised'); - - _approvals[tokenId] = to; - - emit NFTApproval(owner, to, tokenId); - } - - function getApproved(uint256 tokenId) external view returns (address) { - require (_ownerOf[tokenId] !=address(0), "token does not exist"); - return _approvals[tokenId]; - } - - function isApprovedOrOwner(address owner, address spender, uint256 id) private view returns (bool) { - return (spender == owner || isApprovedForAll[owner][spender] || spender == _approvals[id]); - } - - function nftTransferFrom(address from, address to, uint256 tokenId) external { - require(from == _ownerOf[tokenId], "from != owner"); - require(to != address(0), "transfer to zero address"); - require(isApprovedOrOwner(from, msg.sender, tokenId), "not authorised"); - - _balanceOf[from]--; - _balanceOf[to]++; - _ownerOf[tokenId] = to; - - delete _approvals[tokenId]; - } - - function _mintNFT(address to, uint256 tokenId) internal virtual { - require(to != address(0), "mint to zero address"); - require(_ownerOf[tokenId] == address(0), "already minted"); - - _balanceOf[to]++; - _ownerOf[tokenId] = to; - - emit NFTTransfer(address(0), to, tokenId); - } -} diff --git a/Assignments/CrowdFunding.FRANKHOOD/IERC721.sol b/Assignments/CrowdFunding.FRANKHOOD/IERC721.sol deleted file mode 100644 index b06572bf..00000000 --- a/Assignments/CrowdFunding.FRANKHOOD/IERC721.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier:MIT -pragma solidity ^0.8.24; - -interface IERC721 { - function nftBalanceOf(address owner) external view returns (uint256 balance); - function ownerOf(uint tokenId) external view returns (address owner); - //function safeTransferFrom(address from, address to, uint tokenId, bytes memory data) external; - //function safeTransferFrom(address from, address to, uint tokenId) external; - function nftTransferFrom(address from, address to, uint tokenId) external; - function approve(address to, uint256 tokenId) external; - function setApprovalForAll(address operator, bool approved) external; - function isApprovedForAll(address owner, address operator) external view returns (bool); -} \ No newline at end of file diff --git a/Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol b/Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol deleted file mode 100644 index 8af9db35..00000000 --- a/Assignments/CrowdFunding.FRANKHOOD/crowdFunding.sol +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.28; - -import "./ERC20.sol"; -import "./ERC721.sol"; - -/// @title A CrowdFunding Contract -/// @author FRANKHOOD -/// @notice this contract ERC20 and ERC721 tokens from the crowdFunding folder -abstract contract CrowdFund is ERC20, ERC721{ - uint public amount; - uint public _threshhold; - address private crowdFund; - bool TokenClaimed; - bool NFTClaimed; - -/// @notice funder and alreadyClaimed are the addresses that interact with the contract -/// @dev these addresse hold the ERC20 and ERC721 tokens - mapping (address => uint) funder; - mapping (address => uint) alreadyClaimed; - -/// @param _from is the address that calls this function by adding ERC20 to the crowFund -/// @param _amount is the amount of ERC20 added by the _from address - event ContributionMade(address indexed _from, uint _amount); - event TreshholdExceeded(address indexed _from, uint _amount); - -/// @param _to is the address that calls this function by adding ERC20 to the crowFund - event TokenWithdrawn(address indexed _to, uint _amount); - event RewardReceived(address indexed _to, uint _amount); - - -/// @notice this function is payable so it receives the ERC20 tokens -/// @param _from is the address that calls this function by adding ERC20 to the crowFund -/// @param _amount is the amount of ERC20 added by the _from address - function contribution(address _from, uint _amount) payable public { - require(_amount > 0,"Contribution cannot be 0"); - balanceOf[crowdFund] += _amount; - balanceOf[_from] -= _amount; - - funder[_from] += _amount; - TokenClaimed = false;//this argument says that the address has not received reward tokens yet - - emit ContributionMade(_from, _amount); - } - - -/// @notice this function requires the address to contribute an amount greater than 0 to the crowdFund before executing -/// @notice the receiving address cannot be address(0) -/// @notice the tokenClaimed boolean returns as true after the function executes -/// @param _to is the address that calls this function by adding ERC20 to the crowFund -/// @param _amount is the amount of ERC20 added by the _from address - function _mint (address _to, uint256 _amount) virtual override public { - require(TokenClaimed = false, "already claimed reward"); - require(alreadyClaimed[_to] == funder[_to]); - require(funder[_to] > 0,"amount must be greater than 0"); - require(msg.sender != address(0), "zero address"); - balanceOf[_to] += _amount; - totalSupply += _amount; - - TokenClaimed = true;//returns TokenClaimed boolean as true after execuion - - emit Transfer(address(0), _to, _amount); - emit RewardReceived(_to, amount); - } - -/// @notice this function sets the _threshhold at 10 ether and a requirement for execution - function threshhold(address _from, uint _amount) public returns (uint) { - require(_amount >= 10 ether, "not up to 10 ether"); - _threshhold = _amount; - - balanceOf[crowdFund] += _threshhold; - balanceOf[_from] -= _threshhold; - - funder[_from] += _threshhold; - - emit TreshholdExceeded(_from, _amount); - - return _threshhold; - } - - -/// @notice this function does not mint to address 0 and prevents double minting by returning NFTclaimed boolean as true after execuion -/// @param tokenId is the NFT minted when an address reaches the threshhold - function _mintNFT(address _to, uint256 tokenId) internal override { - require(_to != address(0), "mint to zero address"); - require(_ownerOf[tokenId] == address(0), "already minted"); - require(NFTClaimed = false,"Already Claimed"); - require(funder[_to] >= _threshhold); - _balanceOf[_to]++; - _ownerOf[tokenId] = _to; - - NFTClaimed = true;//returns NFTclaimed boolean as true after execuion - - emit Transfer(address(0), _to, tokenId); - emit RewardReceived(_to, amount); - } - - -/// @notice this function enables the user to withdraw their contribution -/// @notice this function requires the amount withdrawable to be less than their contribution - function withrawal(address _to, uint _amount) public { - require(funder[_to] <= funder[_to], "amount withdrawable cannot exceed amount comitted"); - balanceOf[crowdFund] -= _amount; - balanceOf[_to] += _amount; - - emit TokenWithdrawn(_to, _amount); - } -} \ No newline at end of file