Skip to content

Instantly share code, notes, and snippets.

@koolamusic
Last active February 2, 2024 13:50
Show Gist options
  • Save koolamusic/37b9511ad9484d0ff0462ad242c6b48e to your computer and use it in GitHub Desktop.
Save koolamusic/37b9511ad9484d0ff0462ad242c6b48e to your computer and use it in GitHub Desktop.
syndicate.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library ClubLibrary {
struct Club {
uint256 id;
string name;
uint256 minimumToEnter;
mapping(address => Member) members;
uint256 memberCounter;
uint256 pool;
mapping(uint256 => Proposal) proposals;
uint256 proposalCounter;
}
struct Member {
address memberAddress;
uint256 balance;
}
struct Proposal {
uint256 id;
address creator;
uint256 amount;
address destination;
string status;
string description;
uint256 votesFor;
uint256 votesAgainst;
mapping(address => bool) voted;
mapping(uint256 => Comment) comments;
uint256 commentCount;
}
struct Comment {
address commenter;
string text;
}
}
contract InvestmentClub {
using ClubLibrary for ClubLibrary.Club;
struct ClubInfo {
uint256 clubId;
string name;
uint256 memberCount;
uint256 proposalCount;
uint256 pool;
uint256 minimumToEnter;
}
struct ProposalInfo {
uint256 id;
address creator;
uint256 amount;
address destination;
string status;
string description;
uint256 votesFor;
uint256 votesAgainst;
}
struct Vote {
address voter;
bool inSupport;
}
struct ProposalVotes {
uint256 id;
Vote[] votes;
}
mapping(uint256 => ClubLibrary.Club) private clubs;
uint256 private clubCounter;
constructor() {
clubCounter = 0;
}
function getClubById(uint256 clubId) public view returns (ClubInfo memory) {
require(isClubIdExist(clubId), "the club does not exist");
ClubLibrary.Club storage clubReal = clubs[clubId];
ClubInfo memory club = ClubInfo(clubReal.id, clubReal.name, clubReal.memberCounter, clubReal.proposalCounter, clubReal.pool, clubReal.minimumToEnter);
return club;
}
function getMyClubs() public view returns (ClubInfo[] memory) {
ClubInfo[] memory clubsInfo = new ClubInfo[](clubCounter);
uint256 index = 0;
for (uint256 i = 1; i <= clubCounter; i++) {
ClubLibrary.Club storage club = clubs[i];
if (isMemberOfClub(msg.sender, club.id)) {
clubsInfo[index] = ClubInfo(club.id, club.name, club.memberCounter,club.proposalCounter, club.pool, club.minimumToEnter);
index++;
}
}
return clubsInfo;
}
function createClub(string memory name, uint256 minimumToEnter) public returns (uint256) {
uint256 clubId = clubCounter + 1;
ClubLibrary.Club storage club = clubs[clubId];
club.id = clubId;
club.name = name;
club.pool = 0;
club.proposalCounter = 0;
club.memberCounter = 1;
club.minimumToEnter = minimumToEnter;
ClubLibrary.Member memory member = ClubLibrary.Member({
memberAddress: msg.sender,
balance: 0
});
club.members[msg.sender] = member;
clubCounter = clubId;
return clubId;
}
function joinClub(uint256 clubId) public payable {
require(isClubIdExist(clubId), "The club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
//require(isClubFull(clubId), "The club is full, no more members can be added");
require(!isMemberOfClub(msg.sender, clubId), "You are already a member of the club");
require(club.minimumToEnter <= msg.value, "You must contribute to join");
ClubLibrary.Member memory member = ClubLibrary.Member({
memberAddress: msg.sender,
balance: msg.value
});
club.members[msg.sender] = member;
club.memberCounter += 1;
club.pool += uint256(msg.value);
}
function contributeToClub(uint256 clubId) public payable {
require(isClubIdExist(clubId), "the club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
require(isMemberOfClub(msg.sender, clubId), "You are not a member of the club");
require(msg.value > 0, "You must send ETH to contribute");
ClubLibrary.Member storage member = club.members[msg.sender];
member.balance += uint256(msg.value);
club.pool += uint256(msg.value);
}
function createProposal(uint256 clubId, uint256 amount, address destination, string memory description) public {
require(isClubIdExist(clubId), "the club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
require(isMemberOfClub(msg.sender, clubId), "You are not a member of the club");
//require(club.pool >= amount, "The amount exceeds the pool of the club");
require(amount > 0, "The amount of the proposal must be greater than 0");
//require(getBalanceByClub(msg.sender, clubId), "Your balance in the club must be greater than 0");
uint256 proposalId = club.proposalCounter + 1;
ClubLibrary.Proposal storage proposal = clubs[clubId].proposals[proposalId];
proposal.id = proposalId;
proposal.creator = msg.sender;
proposal.amount = amount;
proposal.destination = destination;
proposal.status = "Pending";
proposal.description = description;
proposal.votesFor = 0;
proposal.votesAgainst = 0;
club.proposalCounter = proposalId;
}
// function getVotesForProposal(uint256 clubId, uint256 proposalId) external view returns (address[] memory) {
// require(isClubIdExist(clubId), "Club does not exist");
// require(isProposalIdExist(proposalId, clubId), "Proposal does not exist");
// ClubLibrary.Proposal storage proposal = clubs[clubId].proposals[proposalId];
// uint256 totalVotes = proposal.votesFor+proposal.votesAgainst;
// Vote[] memory votes = new Vote[](totalVotes);
// uint256 index = 0;
// for (uint256 i = 0; i < totalVotes; i++) {
// if (proposal.voted[i]) {
// address voter = proposal.votes[i].voter;
// bool inSupport = proposal.votes[i].inSupport;
// votes[index] = Vote(voter, inSupport);
// index++;
// }
// }
// return votes;
// }
function voteOnProposal(uint256 clubId, uint256 proposalId, bool vote) public {
require(isClubIdExist(clubId), "the club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
require(isMemberOfClub(msg.sender, clubId), "You are not a member of the club");
require(isProposalIdExist(proposalId, clubId), "The proposal does not exist");
//require(getBalanceByClub(msg.sender, clubId) > 0, "Your balance in the club must be greater than 0");
ClubLibrary.Proposal storage proposal = club.proposals[proposalId];
require(!hasVoted(msg.sender, proposalId, clubId), "You have already voted on this proposal");
require(keccak256(bytes(proposal.status)) == keccak256(bytes("Pending")), "The proposal is no longer pending");
proposal.voted[msg.sender] = vote;
if (vote) {
proposal.votesFor += 1;
} else {
proposal.votesAgainst += 1;
}
}
function executeProposal(uint256 clubId, uint256 proposalId) public payable {
require(isClubIdExist(clubId), "the club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
require(isMemberOfClub(msg.sender, clubId), "You are not a member of the club");
require(isProposalIdExist(proposalId, clubId), "The proposal does not exist");
require(isValidExecutor(clubId, proposalId), "Only the creator of the proposal can execute it");
ClubLibrary.Proposal storage proposal = club.proposals[proposalId];
require(club.pool >= proposal.amount, "The amount exceeds the pool of the club");
require(proposal.votesFor > proposal.votesAgainst, "The proposal has not been approved");
proposal.status = "Executed";
club.pool -= proposal.amount;
payable(proposal.destination).transfer(uint256(proposal.amount));
}
function closeProposal(uint256 clubId, uint256 proposalId) public {
require(isClubIdExist(clubId), "the club does not exist");
require(isProposalIdExist(proposalId, clubId), "The proposal does not exist");
ClubLibrary.Proposal storage proposal = clubs[clubId].proposals[proposalId];
require(keccak256(bytes(proposal.status)) == keccak256(bytes("Pending")), "The proposal is not in pending status");
require(isValidExecutor(clubId, proposalId), "Only the proposal creator can close the proposal");
proposal.status = "Closed";
}
function getProposalById(uint256 clubId, uint256 proposalId) public view returns (ProposalInfo memory) {
require(isClubIdExist(clubId), "the club does not exist");
require(isProposalIdExist(proposalId, clubId), "The proposal does not exist");
ClubLibrary.Proposal storage proposal = clubs[clubId].proposals[proposalId];
ProposalInfo memory proposalInfo = ProposalInfo(proposal.id, proposal.creator,
proposal.amount,
proposal.destination,
proposal.status,
proposal.description,
proposal.votesFor,
proposal.votesAgainst);
return proposalInfo;
}
function getProposalsByClub(uint256 clubId) public view returns (ProposalInfo[] memory) {
require(isClubIdExist(clubId), "Club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
ProposalInfo[] memory proposalList = new ProposalInfo[](club.proposalCounter);
uint256 index = 0;
for (uint256 i = 1; i <= club.proposalCounter; i++) {
ClubLibrary.Proposal storage proposal = club.proposals[i];
proposalList[index] = ProposalInfo(
proposal.id,
proposal.creator,
proposal.amount,
proposal.destination,
proposal.status,
proposal.description,
proposal.votesFor,
proposal.votesAgainst
);
index++;
}
return proposalList;
}
function listClubs() public view returns (ClubInfo[] memory) {
ClubInfo[] memory clubList = new ClubInfo[](clubCounter);
for (uint256 i = 0; i < clubCounter; i++) {
ClubLibrary.Club storage club = clubs[i+1];
clubList[i] = ClubInfo(club.id, club.name, club.memberCounter, club.proposalCounter, club.pool, club.minimumToEnter);
}
return clubList;
}
function leaveClub(uint256 clubId) public {
require(isClubIdExist(clubId), "the club does not exist");
ClubLibrary.Club storage club = clubs[clubId];
require(isMemberOfClub(msg.sender, clubId), "You are not a member of the club");
club.memberCounter -= 1;
delete club.members[msg.sender];
}
function isValidExecutor(uint256 clubId, uint256 proposalId) private view returns (bool) {
ClubLibrary.Club storage club = clubs[clubId];
ClubLibrary.Proposal storage proposal = club.proposals[proposalId];
return msg.sender == proposal.creator;
}
function getBalanceByClub(address userAddress, uint256 clubId) public view returns (uint256) {
ClubLibrary.Club storage club = clubs[clubId];
ClubLibrary.Member storage member = club.members[userAddress];
return member.balance;
}
function isClubIdExist(uint256 clubId) public view returns (bool) {
return clubs[clubId].id != 0;
}
function isMemberOfClub(address memberAddress, uint256 clubId) public view returns (bool) {
return clubs[clubId].members[memberAddress].memberAddress != address(0);
}
function isProposalIdExist(uint256 proposalId, uint256 clubId) public view returns (bool) {
return clubs[clubId].proposals[proposalId].id != 0;
}
function hasVoted(address sender, uint256 proposalId, uint256 clubId) public view returns (bool) {
return clubs[clubId].proposals[proposalId].voted[sender];
}
function addComment(uint256 proposalId,uint256 clubId, string memory text) public {
require(isProposalIdExist(proposalId, clubId), "The proposal does not exist");
require(isMemberOfClub(msg.sender, clubId), "You are not a member of the club");
ClubLibrary.Proposal storage proposal = clubs[clubId].proposals[proposalId];
proposal.comments[proposal.commentCount] = ClubLibrary.Comment(msg.sender, text);
proposal.commentCount++;
}
function getComments(uint256 proposalId, uint256 clubId) public view returns (ClubLibrary.Comment[] memory) {
require(isProposalIdExist(proposalId, clubId), "The proposal does not exist");
ClubLibrary.Proposal storage proposal = clubs[clubId].proposals[proposalId];
ClubLibrary.Comment[] memory comments = new ClubLibrary.Comment[](proposal.commentCount);
for (uint256 i = 0; i < proposal.commentCount; i++) {
comments[i] = proposal.comments[i];
}
return comments;
}
// function isClubFull(uint256 clubId) public view returns (bool) {
// return (clubs[clubId].memberCounter < 99);
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment