Skip to content

Instantly share code, notes, and snippets.

@IEnoobong
Created January 24, 2024 09:59
Show Gist options
  • Save IEnoobong/ddb3965b86b5d908359e8e5bb9273b2c to your computer and use it in GitHub Desktop.
Save IEnoobong/ddb3965b86b5d908359e8e5bb9273b2c to your computer and use it in GitHub Desktop.
Coinbase's Base Bootcamp codes
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";
contract AddressBook is Ownable {
struct Contact {
uint id;
string firstName;
string lastName;
uint[] phoneNumbers;
}
mapping(address => Contact[]) contacts;
constructor(address _ownerAddress) Ownable(_ownerAddress) {
}
function addContact(uint _id, string memory _firstName, string memory _lastName, uint[] memory _phoneNumbers) external onlyOwner {
contacts[msg.sender].push(Contact(_id, _firstName, _lastName, _phoneNumbers));
}
error ContactNotFound(uint _id);
function deleteContact(uint _id) external onlyOwner {
Contact[] storage userContacts = contacts[msg.sender];
uint contactsSize = _validateContactSize(userContacts, _id);
bool foundContact = false;
for (uint i = 0; i < contactsSize; i++) {
if (userContacts[i].id == _id) {
foundContact = true;
delete userContacts[i];
}
}
if (!foundContact) {
revert ContactNotFound(_id);
}
}
function _validateContactSize(Contact[] memory _contacts, uint _id) private pure returns (uint) {
uint contactsSize = _contacts.length;
if (contactsSize == 0) {
revert ContactNotFound(_id);
}
return contactsSize;
}
function getContact(uint _id) external view returns (Contact memory){
Contact[] memory userContacts = contacts[msg.sender];
uint contactsSize = _validateContactSize(userContacts, _id);
for (uint i = 0; i < contactsSize; i++) {
Contact memory userContact = userContacts[i];
if (userContact.id == _id) {
return userContact;
}
}
revert ContactNotFound(_id);
}
function getAllContacts() external view returns(Contact[] memory) {
return contacts[msg.sender];
}
}
contract AddressBookFactory {
function deploy() external returns (address) {
AddressBook newAddressBook = new AddressBook(msg.sender);
return address(newAddressBook);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract ArrayDemo {
uint8[] public numbers;
uint8 numEven;
function getEvenNumbers() external view returns (uint8[] memory) {
uint8[] memory evenNumbers = new uint8[](numEven);
uint8 cursor = 0;
for (uint8 i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 == 0) {
evenNumbers[cursor] = numbers[i];
cursor++;
}
}
return evenNumbers;
}
function debugLoadArray(uint8 _number) external {
for(uint8 i = 0; i < _number; i++) {
numbers.push(i);
if(i % 2 == 0) {
numEven++;
}
}
}
function _countEvenNumber() internal view returns (uint8) {
uint8 count = 0;
for (uint8 i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 == 0) {
count++;
}
}
return count;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract ArraysExercise {
uint[] public numbers = [1,2,3,4,5,6,7,8,9,10];
function getNumbers() external view returns (uint[] memory) {
return numbers;
}
function resetNumbers() public {
for (uint8 i = 0; i < 10; i++) {
numbers[i] = i + 1;
}
}
function appendToNumbers(uint[] calldata _toAppend) external {
for (uint i = 0; i < _toAppend.length; i++) {
numbers.push(_toAppend[i]);
}
}
uint[] timestamps;
address[] senders;
function saveTimestamp(uint _unixTimestamp) external {
timestamps.push(_unixTimestamp);
senders.push(msg.sender);
}
uint256 constant Y2K_TIMESTAMP = 946702800;
function afterY2K() external view returns (uint[] memory, address[] memory){
uint afterY2KCount = 0;
for (uint i = 0; i < timestamps.length; i++) {
if (timestamps[i] > Y2K_TIMESTAMP) {
afterY2KCount++;
}
}
uint256[] memory recentTimestamps = new uint256[](afterY2KCount);
address[] memory respectiveSenders = new address[](afterY2KCount);
uint index = 0;
for (uint i = 0; i < timestamps.length; i++) {
if (timestamps[i] > Y2K_TIMESTAMP) {
recentTimestamps[index] = timestamps[i];
respectiveSenders[index] = senders[i];
index++;
}
}
return (recentTimestamps, respectiveSenders);
}
function resetSenders() public {
delete senders;
}
function resetTimestamps() public {
delete timestamps;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract BasicMath {
function adder(uint _a, uint _b) external pure returns (uint sum, bool error) {
unchecked {
uint c =_a + _b;
if (c >= _a) {
return (c, false);
} else {
return (0, true);
}
}
}
function subtractor(uint _a, uint _b) external pure returns (uint difference, bool error) {
unchecked {
if (_b > _a) {
return (0, true);
} else {
return (_a - _b, false);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Complimenter {
string public name;
constructor(string memory _name) {
name = _name;
}
function compliment() external view returns (string memory) {
return string.concat("You look great today, ", name, "!");
}
}
contract ComplimentFactory {
function CreateComplimenter(string memory _name) public returns (address) {
Complimenter newContract = new Complimenter(_name);
return address(newContract);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract ControlStructures {
function fizzBuzz(uint _number) external pure returns (string memory) {
if (_number % 3 == 0 && _number % 5 == 0) {
return "FizzBuzz";
} else if (_number % 3 == 0) {
return "Fizz";
} else if (_number % 5 == 0) {
return "Buzz";
} else {
return "Splat";
}
}
error AfterHours(uint _time);
error IllegalTime(uint _time);
function doNotDisturb(uint _time) external pure returns (string memory) {
assert(_time <= 2400);
if (_time > 2200 || _time < 800) {
revert AfterHours(_time);
} else if (_time >= 1200 && _time <= 1259){
return "At lunch!";
} else if (_time >= 800 && _time <= 1199){
return "Morning!";
} else if (_time >= 1300 && _time <= 1799){
return "Afternoon!";
} else if (_time >= 1800 && _time <=2200){
return "Evening!";
} else {
revert IllegalTime(_time);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract EmployeeStorage {
uint16 shares;
uint32 salary;
uint256 public idNumber;
string public name;
constructor(uint16 _shares, uint32 _salary, uint256 _idNumber, string memory _name) {
shares = _shares;
salary = _salary;
idNumber = _idNumber;
name = _name;
}
function viewSalary() external view returns (uint32) {
return salary;
}
function viewShares() external view returns (uint16) {
return shares;
}
error TooManyShares(uint16 _newTotalShares);
function grantShares(uint16 _newShares) external {
require(_newShares <= 5000, "Too many shares");
uint16 total = shares + _newShares;
if (total > 5000) {
revert TooManyShares(total);
} else {
shares = total;
}
}
/**
* Do not modify this function. It is used to enable the unit test for this pin
* to check whether or not you have configured your storage variables to make
* use of packing.
*
* If you wish to cheat, simply modify this function to always return `0`
* I'm not your boss ¯\_(ツ)_/¯
*
* Fair warning though, if you do cheat, it will be on the blockchain having been
* deployed by you wallet....FOREVER!
*/
function checkForPacking(uint _slot) public view returns (uint r) {
assembly {
r := sload (_slot)
}
}
/**
* Warning: Anyone can use this function at any time!
*/
function debugResetShares() public {
shares = 1000;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract ErrorTriageExercise {
/**
* Finds the difference between each uint with it's neighbor (a to b, b to c, etc.)
* and returns a uint array with the absolute integer difference of each pairing.
*/
function diffWithNeighbor(
uint _a,
uint _b,
uint _c,
uint _d
) public pure returns (uint[] memory) {
uint[] memory results = new uint[](3);
results[0] = _absoluteDifference(_a, _b);
results[1] = _absoluteDifference(_b, _c);
results[2] = _absoluteDifference(_c, _d);
return results;
}
function _absoluteDifference(uint _a, uint _b) private pure returns (uint) {
return _a > _b ? _a - _b : _b - _a;
}
/**
* Changes the _base by the value of _modifier. Base is always >= 1000. Modifiers can be
* between positive and negative 100;
*/
function applyModifier(
uint _base,
int _modifier
) public pure returns (uint) {
if (_modifier < 0) {
return _base - uint(-_modifier);
}
return _base + uint(_modifier);
}
/**
* Pop the last element from the supplied array, and return the modified array and the popped
* value (unlike the built-in function)
*/
uint[] arr;
function popWithReturn() public returns (uint) {
uint arrayLength = arr.length;
require(arrayLength > 0, "Empty array");
uint index = arrayLength - 1;
uint element = arr[index];
arr.pop();
return element;
}
// The utility functions below are working as expected
function addToArr(uint _num) public {
arr.push(_num);
}
function getArr() public view returns (uint[] memory) {
return arr;
}
function resetArr() public {
delete arr;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract FavoriteRecords {
mapping (string => bool) public approvedRecords;
mapping (address => mapping (string => bool)) userFavorites;
string[] private approvedRecordsNames = ["Thriller", "Back in Black", "The Bodyguard", "The Dark Side of the Moon", "Their Greatest Hits (1971-1975)", "Hotel California", "Come On Over", "Rumours", "Saturday Night Fever"];
constructor() {
for (uint8 i = 0; i < approvedRecordsNames.length; i++) {
approvedRecords[approvedRecordsNames[i]] = true;
}
}
function getApprovedRecords() external view returns (string[] memory) {
return approvedRecordsNames;
}
error NotApproved(string _albumName);
function addRecord(string memory _albumName) external {
if (approvedRecords[_albumName]) {
userFavorites[msg.sender][_albumName] = true;
} else {
revert NotApproved(_albumName);
}
}
function getUserFavorites(address _address) external view returns (string[] memory) {
uint8 count = 0;
for (uint8 i = 0; i < approvedRecordsNames.length; i++) {
if (userFavorites[_address][approvedRecordsNames[i]]) {
count++;
}
}
string[] memory userFavoriteAlbums = new string[](count);
uint8 index = 0;
for (uint8 i = 0; i < approvedRecordsNames.length; i++) {
string memory _albumName = approvedRecordsNames[i];
if (userFavorites[_address][_albumName]) {
userFavoriteAlbums[index] = _albumName;
index++;
}
}
return userFavoriteAlbums;
}
function resetUserFavorites() external {
for (uint8 i = 0; i < approvedRecordsNames.length; i++) {
delete userFavorites[msg.sender][approvedRecordsNames[i]];
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract GarageManager {
struct Car {
string make;
string model;
string color;
uint numberOfDoors;
}
mapping (address => Car[]) public garage;
function addCar(string memory _make, string memory _model, string memory _color, uint _numberOfDoors) external {
Car[] storage userCars = garage[msg.sender];
userCars.push(Car(_make, _model, _color, _numberOfDoors));
}
function getMyCars() external view returns (Car[] memory) {
return garage[msg.sender];
}
function getUserCars(address _address) external view returns (Car[] memory) {
return garage[_address];
}
error BadCarIndex(uint _index);
function updateCar(uint _index, string memory _make, string memory _model, string memory _color, uint _numberOfDoors) external {
Car[] storage userCars = garage[msg.sender];
if (_index >= userCars.length) {
revert BadCarIndex(_index);
}
userCars[_index] = Car(_make, _model, _color, _numberOfDoors);
}
function resetMyGarage() public {
delete garage[msg.sender];
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
contract HaikuNFT is ERC721 {
constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {
}
struct Haiku {
address author;
string line1;
string line2;
string line3;
}
Haiku[] public haikus;
mapping (address => uint[]) sharedHaikus;
mapping(string => bool) private usedLines;
uint public counter = 1;
error HaikuNotUnique();
function mintHaiku(string memory _line1, string memory _line2, string memory _line3) external {
if (usedLines[_line1] || usedLines[_line2] || usedLines[_line3]) {
revert HaikuNotUnique();
}
address author = _msgSender();
uint tokenId = counter;
_mint(author, tokenId);
Haiku memory newHaiku = Haiku({
author: author,
line1: _line1,
line2: _line2,
line3: _line3
});
haikus.push(newHaiku);
usedLines[_line1] = true;
usedLines[_line2] = true;
usedLines[_line3] = true;
counter++;
}
error NotYourHaiku();
function shareHaiku(address _to, uint256 _tokenId) public {
require(_to != address(0), "Invalid Address");
if (ownerOf(_tokenId) != _msgSender()){
revert NotYourHaiku();
}
sharedHaikus[_to].push(_tokenId);
}
error NoHaikusShared();
function getMySharedHaikus() public view returns (uint256[] memory) {
uint256[] memory mySharedHaikus = sharedHaikus[_msgSender()];
if (mySharedHaikus.length == 0) {
revert NoHaikusShared();
}
return mySharedHaikus;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
library SillyStringUtils {
struct Haiku {
string line1;
string line2;
string line3;
}
function shruggie(string memory _input) internal pure returns (string memory) {
return string.concat(_input, unicode" 🤷");
}
}
contract ImportsExercise {
using SillyStringUtils for SillyStringUtils.Haiku;
SillyStringUtils.Haiku public haiku;
function saveHaiku(string memory _line1, string memory _line2, string memory _line3) external {
haiku = SillyStringUtils.Haiku(_line1, _line2, _line3);
}
function getHaiku() external view returns(SillyStringUtils.Haiku memory) {
return haiku;
}
function shruggieHaiku() external view returns (SillyStringUtils.Haiku memory){
return SillyStringUtils.Haiku(haiku.line1, haiku.line2, SillyStringUtils.shruggie(haiku.line3));
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
abstract contract ContractD {
function whoAreYou() public virtual view returns(string memory);
}
contract ContractC {
function whoAmI() virtual external pure returns (string memory) {
return "contract C";
}
}
contract ContractB {
function whoAmI() virtual external pure returns (string memory) {
return "contract B";
}
function whoAmIInternal() internal pure returns (string memory) {
return "contract B";
}
function whoAmIPrivate() private pure returns (string memory) {
return "contract B";
}
}
contract ContractA is ContractB, ContractC, ContractD {
enum Type { None, ContractBType, ContractCType }
Type contractType;
function whoAmI() override(ContractB, ContractC) external pure returns (string memory) {
return "contract A";
}
function whoAmExternal() external pure returns (string memory) {
return whoAmIInternal();
// return whoAmIPrivate();
}
function whoAreYou() public override pure returns(string memory){
return "Je suis une personne";
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
abstract contract Employee {
uint56 public idNumber;
uint56 public managerId;
constructor(uint56 _idNumber, uint56 _managerId) {
idNumber = _idNumber;
managerId = _managerId;
}
function getAnnualCost() external virtual returns (uint);
}
contract Salaried is Employee {
uint72 public annualSalary;
constructor(uint72 _annualSalary, uint56 _idNumber, uint56 _managerId) Employee(_idNumber, _managerId) {
annualSalary = _annualSalary;
}
function getAnnualCost() external override view returns (uint){
return annualSalary;
}
}
contract Hourly is Employee {
uint72 public hourlyRate;
constructor(uint72 _hourlyRate, uint56 _idNumber, uint56 _managerId) Employee(_idNumber, _managerId) {
hourlyRate = _hourlyRate;
}
function getAnnualCost() external override view returns (uint){
return hourlyRate * 2080;
}
}
contract Manager is Salaried {
uint56[] public employeeIds;
constructor(uint72 _annualSalary, uint56 _idNumber, uint56 _managerId) Salaried(_annualSalary, _idNumber, _managerId) {
}
function addReport(uint56 _employeeId) external {
employeeIds.push(_employeeId);
}
function resetReports() external {
delete employeeIds;
}
}
contract Salesperson is Hourly {
constructor(uint72 _hourlyRate, uint24 _idNumber, uint24 _managerId) Hourly(_hourlyRate, _idNumber, _managerId) {
}
}
contract EngineeringManager is Salaried, Manager {
constructor(uint72 _annualSalary, uint56 _idNumber, uint56 _managerId) Manager(_annualSalary, _idNumber, _managerId) {
}
}
contract InheritanceSubmission {
address public salesPerson;
address public engineeringManager;
constructor(address _salesPerson, address _engineeringManager) {
salesPerson = _salesPerson;
engineeringManager = _engineeringManager;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Mappings {
mapping (address => uint) public favoriteNumbers;
address[] addressOfFavs;
// function saveFavoriteNumber(address _address, uint _favourite) public {
// favoriteNumbers[_address] = _favourite;
// addressOfFavs.push(_address);
// }
function saveFavoriteNumber(uint _favourite) public {
if (favoriteNumbers[msg.sender] == 0) {
addressOfFavs.push(msg.sender);
}
favoriteNumbers[msg.sender] = _favourite;
}
function returnAllFavourites() public view returns (uint[] memory) {
uint[] memory _favoriteNumbers = new uint[](addressOfFavs.length);
for (uint i = 0; i < _favoriteNumbers.length; i++) {
_favoriteNumbers[i] = favoriteNumbers[addressOfFavs[i]];
}
return _favoriteNumbers;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract MinimalToken {
mapping (address => uint) public balances;
uint public totalSupply;
constructor() {
totalSupply = 3000;
balances[msg.sender] = totalSupply / 3;
balances[0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2] = totalSupply / 3;
balances[0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db] = totalSupply / 3;
}
error InsufficientTokens(int _amount);
function transfer(address _to, uint _amount) external {
// require(balances[msg.sender] >= _amount, "Insufficient funds");
int newSenderBalance = int(balances[msg.sender] - _amount);
if (newSenderBalance < 0) {
revert InsufficientTokens(newSenderBalance);
}
balances[msg.sender] = uint(newSenderBalance);
// balances[msg.sender] -= _amount;
balances[_to] += _amount;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Modifiers {
address owner;
constructor() {
owner = msg.sender;
}
error NotOwner(address _msgSender);
modifier onlyOwner {
if (owner != msg.sender) {
revert NotOwner(msg.sender);
}
_;
}
function iOwnThis() external onlyOwner view returns (string memory) {
return "I own this";
}
error NotEven(uint _number);
modifier onlyEven(uint _number) {
if (_number % 2 != 0){
revert NotEven(_number);
}
_;
}
function halver(uint _number) external pure onlyEven(_number) returns (uint) {
return _number / 2;
}
// Bad code example, does not work
modifier doubler(uint _number) {
_number *= 2;
_;
}
function modifierDoubler(uint _number) public pure doubler(_number) returns (uint) {
return _number; // Returns the original number, NOT number * 2
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
contract MyERC20Token is ERC20 {
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
_mint(msg.sender, 1 * 10**18);
_mint(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2, 1 * 10**18);
_mint(0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db, 1 * 10**18);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol";
contract MyERC721Token is ERC721 {
string constant BAYC = "https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/";
string constant DOODLES = "https://ipfs.io/ipfs/QmPMc4tcBsMqLRuCQtPmPe84bpSjrC3Ky7t3JWuHXYB4aS/";
enum NFTMetadata { BAYC, DOODLES }
NFTMetadata nftMetadata = NFTMetadata.BAYC;
uint private counter = 1;
constructor(string memory _name, string memory _token) ERC721(_name, _token) {
}
function redeemNFT() external {
_safeMint(msg.sender, ++counter);
}
function _baseURI() internal override view returns(string memory) {
if (nftMetadata == NFTMetadata.BAYC) {
return BAYC;
} else if (nftMetadata == NFTMetadata.DOODLES){
return DOODLES;
} else {
revert("Error...");
}
}
function switchURI() public {
// TODO: Limit to contract owner
nftMetadata = nftMetadata == NFTMetadata.BAYC ? NFTMetadata.DOODLES : NFTMetadata.BAYC;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol";
contract SetExploration {
using EnumerableSet for EnumerableSet.AddressSet;
EnumerableSet.AddressSet private visitors;
function registerVisitor() external {
visitors.add(msg.sender);
}
function numberOfVisistors() external view returns (uint) {
return visitors.length();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract UnburnableToken {
mapping (address => uint) public balances;
uint public totalSupply;
uint public totalClaimed;
mapping (address => bool) private claimedAddressses;
constructor() {
totalSupply = 100000000;
}
uint private constant MAX_CLAIM_AMOUNT = 1000;
error TokensClaimed();
error AllTokensClaimed();
function claim() public {
// require(totalClaimed + MAX_CLAIM_AMOUNT <= totalSupply, "Insufficient claimable funds");
if (totalClaimed == totalSupply) {
revert AllTokensClaimed();
}
if (claimedAddressses[msg.sender]) {
revert TokensClaimed();
}
claimedAddressses[msg.sender] = true;
totalClaimed += MAX_CLAIM_AMOUNT;
balances[msg.sender] += MAX_CLAIM_AMOUNT;
}
error UnsafeTransfer(address _address);
function safeTransfer(address _to, uint _amount) public {
require(balances[msg.sender] >= _amount, "Insufficient funds");
// require(msg.sender == _to, "Self transfer not allowed");
if (_to == address(0) || _to.balance == 0){
revert UnsafeTransfer(_to);
}
balances[msg.sender] -= _amount;
balances[_to] += _amount;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/EnumerableSet.sol";
contract WeightedVoting is ERC20 {
uint constant private MAX_SUPPLY = 1_000_000;
uint constant private MAX_CLAIM_AMOUNT = 100;
using EnumerableSet for EnumerableSet.AddressSet;
struct Issue {
EnumerableSet.AddressSet voters;
string issueDesc;
uint votesFor;
uint votesAgainst;
uint votesAbstain;
uint totalVotes;
uint quorum;
bool passed;
bool closed;
}
Issue[] private issues;
enum Votes {AGAINST, FOR, ABSTAIN }
mapping (address => bool) private claimedAddressses;
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
Issue storage newIssue = issues.push();
newIssue.issueDesc = "Burnt";
newIssue.closed = true;
}
error TokensClaimed();
error AllTokensClaimed();
error NoTokensHeld();
error QuorumTooHigh(uint _proposedAmount);
error AlreadyVoted();
error VotingClosed();
function claim() public {
if (MAX_SUPPLY == totalSupply()) {
revert AllTokensClaimed();
}
address sender = _msgSender();
if (claimedAddressses[sender]) {
revert TokensClaimed();
}
claimedAddressses[sender] = true;
_mint(sender, MAX_CLAIM_AMOUNT);
}
function createIssue(string memory _issueDesc, uint _quorum) external returns(uint) {
address sender = _msgSender();
uint senderBalance = balanceOf(sender);
if (senderBalance == 0) {
revert NoTokensHeld();
}
if (_quorum > totalSupply()) {
revert QuorumTooHigh(_quorum);
}
Issue storage newIssue = issues.push();
newIssue.issueDesc = _issueDesc;
newIssue.quorum = _quorum;
return issues.length - 1;
}
struct ReturnableIssue {
address[] voters;
string issueDesc;
uint votesFor;
uint votesAgainst;
uint votesAbstain;
uint totalVotes;
uint quorum;
bool passed;
bool closed;
}
function numberOfIssues() public view returns(uint) {
return issues.length;
}
function getAllIssues() public view returns(ReturnableIssue[] memory) {
ReturnableIssue[] memory allIssues = new ReturnableIssue[](issues.length);
for(uint i = 0; i < issues.length; i++) {
allIssues[i] = getIssue(i);
}
return allIssues;
}
function getIssue(uint _id) public view returns (ReturnableIssue memory) {
require(_id < issues.length, "Invalid issue id");
Issue storage issue = issues[_id];
EnumerableSet.AddressSet storage votersSet = issue.voters;
address[] memory voters = new address[](votersSet.length());
for (uint256 i = 0; i < votersSet.length(); i++) {
voters[i] = votersSet.at(i);
}
return ReturnableIssue(
voters,
issue.issueDesc,
issue.votesFor,
issue.votesAgainst,
issue.votesAbstain,
issue.totalVotes,
issue.quorum,
issue.passed,
issue.closed
);
}
function vote(uint _issueId, Votes _vote) public {
require(_issueId < issues.length, "Invalid id");
Issue storage issue = issues[_issueId];
if (issue.closed) {
revert VotingClosed();
}
address voter = _msgSender();
if (issue.voters.contains(voter)){
revert AlreadyVoted();
}
issue.voters.add(voter);
uint voterBalance = balanceOf(voter);
if (_vote == Votes.AGAINST) {
issue.votesAgainst += voterBalance;
} else if (_vote == Votes.FOR) {
issue.votesFor += voterBalance;
} else if (_vote == Votes.ABSTAIN) {
issue.votesAbstain += voterBalance;
}
issue.totalVotes += voterBalance;
if (issue.totalVotes >= issue.quorum) {
issue.closed = true;
issue.passed = issue.votesFor > issue.votesAgainst;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment