From 9a75443007476121bf6fe5cd5d2bb9bb28fd9d2d Mon Sep 17 00:00:00 2001 From: enyinnaya1234 Date: Sat, 15 Feb 2025 21:47:51 +0100 Subject: [PATCH 1/2] feat: add crowdfunding contract --- .../enyinnaya1234/CrowdFundingContract.sol | 55 +++++++++++++++++++ .../Assignment3/enyinnaya1234/ERC20.sol | 40 ++++++++++++++ .../Assignment3/enyinnaya1234/ERC721.sol | 25 +++++++++ .../Assignment3/enyinnaya1234/IERC20.sol | 8 +++ .../Assignment3/enyinnaya1234/IERC721.sol | 7 +++ 5 files changed, 135 insertions(+) create mode 100644 submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol create mode 100644 submissions/Assignment3/enyinnaya1234/ERC20.sol create mode 100644 submissions/Assignment3/enyinnaya1234/ERC721.sol create mode 100644 submissions/Assignment3/enyinnaya1234/IERC20.sol create mode 100644 submissions/Assignment3/enyinnaya1234/IERC721.sol diff --git a/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol b/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol new file mode 100644 index 00000000..dd9d8d12 --- /dev/null +++ b/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.24; + +import "./ERC20.sol"; +import "./ERC721.sol"; + +contract CrowdFundingContract{ + bool public fundingGoalMet; + uint public fundingThreshold; + uint public fundingGoal; + address public owner; + + // Mapping + mapping(address => uint256) public _tokenBalances; + mapping(address => uint256) public _contributions; + + // Events + Events trackContributions(address contributor, uint amount); + + constructor(uint memory _fundingGoal, uint memory _fundingThreshold){ + _fundingGoal = fundingGoal; + _fundingThreshold = fundingThreshold; + owner = msg.sender; + } + + // modifiers + modifier onlyOwner(){ + require(msg.sender == owner, "Not owner"); + + _; + } + + // Functions + + // Tracking contributions + // Contribution exceed a set threshold, mint an ERC721 NFT + and send to contributor's account + function exceedThreshold(address from, uint tokenId, address to ) external { + _contributions[from] = msg.value; + if(_contributions[from][msg.value] > _fundingThreshold){ + ERC721._mint(to, tokenId); + } + else{ + ERC20._mint(contributor, msg.value); + } + } + + // Project owner can withdraw funds if a funding goal is met + function goalIsMet() onlyOwner { + if (fundingGoalMet){ + // withdraw funds + + } +} \ No newline at end of file diff --git a/submissions/Assignment3/enyinnaya1234/ERC20.sol b/submissions/Assignment3/enyinnaya1234/ERC20.sol new file mode 100644 index 00000000..28b0eefc --- /dev/null +++ b/submissions/Assignment3/enyinnaya1234/ERC20.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.24; + +import "./IERC20.sol"; + +contract ERC20 is IERC20{ + string public name; + string public symbol; + uint8 public decimals; + uint256 public totalSupply; + + mapping(address => uint256) public balance; + //mapping(address) + + event Transfer(address indexed _from, address indexed _to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 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, "Insufficient funds"); + balanceOf[msg.sender] -= amount; + balanceOf[recipient] += amount; + + emit Transfer(msg.sender, recipient, amount); + } + + function mint(address _to, uint256 _amount) external{ + require(msg.sender != address(0), "zero address"); + balanceOf[_to] += _amount; + totalSupply += _amount; + + emit Transfer(address(0), _to, _amount); + } +} \ No newline at end of file diff --git a/submissions/Assignment3/enyinnaya1234/ERC721.sol b/submissions/Assignment3/enyinnaya1234/ERC721.sol new file mode 100644 index 00000000..704a41cd --- /dev/null +++ b/submissions/Assignment3/enyinnaya1234/ERC721.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.24; + +import "./IERC721.sol"; + +contract ERC721 is IERC721{ + // Mapping + mapping(uint256 => address) internal _ownerOf; + mapping(address => uint256) internal _balanceOf; + + // event + event Transfer(address indexed from, address indexed to, uint256 indexed id); + + function _mint(address to, uint256 tokenId) internal{ + require(to != address(0), "mint to zero address"); + require(_ownerOf[tokenId] == address(0), "already minted"); + + _balanceOf[to]++; + _ownerOf[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + } + +} \ No newline at end of file diff --git a/submissions/Assignment3/enyinnaya1234/IERC20.sol b/submissions/Assignment3/enyinnaya1234/IERC20.sol new file mode 100644 index 00000000..e3eaf609 --- /dev/null +++ b/submissions/Assignment3/enyinnaya1234/IERC20.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.24; + +interface IERC20{ + function transfer(address recipient, uint256 amount) external returns (bool); + function mint(address _to, uint256 _amount) external; +} \ No newline at end of file diff --git a/submissions/Assignment3/enyinnaya1234/IERC721.sol b/submissions/Assignment3/enyinnaya1234/IERC721.sol new file mode 100644 index 00000000..9a3db19c --- /dev/null +++ b/submissions/Assignment3/enyinnaya1234/IERC721.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.24; + +interface IERC721{ + function _mint(address to, uint256 tokenId) external; +} \ No newline at end of file From c7036ae3a2294399ad1ace89991f98a30570be5f Mon Sep 17 00:00:00 2001 From: enyinnaya1234 Date: Wed, 19 Feb 2025 00:57:18 +0100 Subject: [PATCH 2/2] feat: add crowdfunding contract --- .../enyinnaya1234/CrowdFundingContract.sol | 55 +++++++++++-------- .../Assignment3/enyinnaya1234/ERC20.sol | 23 +++++--- .../Assignment3/enyinnaya1234/ERC721.sol | 14 ++++- 3 files changed, 59 insertions(+), 33 deletions(-) diff --git a/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol b/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol index dd9d8d12..babcdadb 100644 --- a/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol +++ b/submissions/Assignment3/enyinnaya1234/CrowdFundingContract.sol @@ -6,50 +6,61 @@ import "./ERC20.sol"; import "./ERC721.sol"; contract CrowdFundingContract{ - bool public fundingGoalMet; + bool public fundingGoalMet = false; uint public fundingThreshold; uint public fundingGoal; address public owner; + // initialize imported files + ERC20 private erc20; + ERC721 private erc721; + // Mapping mapping(address => uint256) public _tokenBalances; mapping(address => uint256) public _contributions; // Events - Events trackContributions(address contributor, uint amount); + event trackContributions(address contributor, uint amount); - constructor(uint memory _fundingGoal, uint memory _fundingThreshold){ - _fundingGoal = fundingGoal; - _fundingThreshold = fundingThreshold; + constructor(uint _fundingGoal, uint _fundingThreshold, address payable Erc20Address, address Erc721Address){ + fundingGoal = _fundingGoal; + fundingThreshold = _fundingThreshold; owner = msg.sender; + erc20 = ERC20(Erc20Address); //0xdA36e707Af22009FA453Fe3D2707c510C8E4AC46 + erc721 = ERC721(Erc721Address); //0xee41a93503C6007c72BbfEc027412430B3c743F0 } + // modifiers modifier onlyOwner(){ - require(msg.sender == owner, "Not owner"); - + require(msg.sender == owner, "Not owner"); _; - } + } // Functions - // Tracking contributions - // Contribution exceed a set threshold, mint an ERC721 NFT - and send to contributor's account - function exceedThreshold(address from, uint tokenId, address to ) external { - _contributions[from] = msg.value; - if(_contributions[from][msg.value] > _fundingThreshold){ - ERC721._mint(to, tokenId); + // Contribution exceed a set threshold, mint an ERC721 NFT and send to contributor's account + function exceedThreshold(address to ) external onlyOwner payable { + if (address(this).balance < fundingGoal){ + require(msg.value > 0, "contributions must be above 0"); + _contributions[msg.sender] += msg.value; + if(msg.value > fundingThreshold){ + uint256 tokenId = uint256(keccak256(abi.encodePacked(msg.sender))); + erc721._mint(to, tokenId); + } + else{ + erc20.mint(to, msg.value); + } } else{ - ERC20._mint(contributor, msg.value); + // withdraw funds + uint balance = address(this).balance; + address payable sendTo = payable(owner); + sendTo.transfer(balance); + fundingGoalMet = true; } + } - // Project owner can withdraw funds if a funding goal is met - function goalIsMet() onlyOwner { - if (fundingGoalMet){ - // withdraw funds - - } + } \ No newline at end of file diff --git a/submissions/Assignment3/enyinnaya1234/ERC20.sol b/submissions/Assignment3/enyinnaya1234/ERC20.sol index 28b0eefc..e3bc864f 100644 --- a/submissions/Assignment3/enyinnaya1234/ERC20.sol +++ b/submissions/Assignment3/enyinnaya1234/ERC20.sol @@ -2,32 +2,39 @@ pragma solidity ^0.8.24; -import "./IERC20.sol"; -contract ERC20 is IERC20{ +contract ERC20 { + error FunctionDoesNotExist(); string public name; string public symbol; - uint8 public decimals; + uint8 public decimals ; uint256 public totalSupply; - mapping(address => uint256) public balance; + mapping(address => uint256) public balanceOf; //mapping(address) event Transfer(address indexed _from, address indexed _to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); - constructor(string memory _name, string memory _symbol, uint8 _decimals){ - name = _name; - symbol = _symbol; - decimals = _decimals; + constructor(uint _totalSupply, string memory _name, string memory _symbol, uint8 _decimals){ + _totalSupply = totalSupply; + _name = name; + _symbol = symbol; + _decimals = decimals; } + receive() external payable{} + fallback() external payable{ + revert FunctionDoesNotExist(); + } + function transfer(address recipient, uint256 amount) external returns (bool){ require(balanceOf[msg.sender] >= amount, "Insufficient funds"); balanceOf[msg.sender] -= amount; balanceOf[recipient] += amount; emit Transfer(msg.sender, recipient, amount); + return true; } function mint(address _to, uint256 _amount) external{ diff --git a/submissions/Assignment3/enyinnaya1234/ERC721.sol b/submissions/Assignment3/enyinnaya1234/ERC721.sol index 704a41cd..58f29ff3 100644 --- a/submissions/Assignment3/enyinnaya1234/ERC721.sol +++ b/submissions/Assignment3/enyinnaya1234/ERC721.sol @@ -2,9 +2,8 @@ pragma solidity ^0.8.24; -import "./IERC721.sol"; -contract ERC721 is IERC721{ +contract ERC721 { // Mapping mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; @@ -12,7 +11,7 @@ contract ERC721 is IERC721{ // event event Transfer(address indexed from, address indexed to, uint256 indexed id); - function _mint(address to, uint256 tokenId) internal{ + function _mint(address to, uint256 tokenId) external{ require(to != address(0), "mint to zero address"); require(_ownerOf[tokenId] == address(0), "already minted"); @@ -22,4 +21,13 @@ contract ERC721 is IERC721{ emit Transfer(address(0), to, tokenId); } + function balanceOf(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"); +} } \ No newline at end of file