Skip to content

Instantly share code, notes, and snippets.

@trinhvandat
Created April 7, 2023 18:07
Show Gist options
  • Save trinhvandat/cf40d63100f2ca3b188ba5a60dc73996 to your computer and use it in GitHub Desktop.
Save trinhvandat/cf40d63100f2ca3b188ba5a60dc73996 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.18+commit.87f61d96.js&optimize=false&runs=200&gist=
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
import "hardhat/console.sol";
contract FundDecentralize {
/*================= STRUCT =====================*/
struct Member {
string name;
uint piority;
}
struct MemberInVote {
string joinerName;
uint joinerPiority;
uint totalAgree;
bool isDone;
bool isCreated;
uint totalPiorityVoted;
}
struct MemberOutVote {
uint totalAgree;
bool isDone;
bool isCreated;
uint totalPiorityVoted;
}
struct WithdrawVote {
uint amount;
string reason;
uint totalAgree;
bool isDone;
bool isCreated;
uint totalPiorityVoted;
}
struct TrusteeWithdrawVote {
WithdrawVote withdrawVote;
bool isDone;
bool isCreated;
uint totalPiorityVoted;
mapping(address => uint) trusteeVoteds;
address[] trusteesAddress;
bool isWithdraw;
address trusteeChoosen;
}
/*================= STRUCT =====================*/
/*================= STAGE =====================*/
mapping(address => Member) members;
uint256 private totalMember;
uint private totalMemberPiority;
uint private expireTimeFreeJoin;
uint private percentPassVote;
uint256 private amountLock;
mapping(address => MemberInVote) private memberInVotes;
mapping(address => MemberOutVote) private memberOutVotes;
mapping(uint => WithdrawVote) private withdrawVotes;
mapping(uint => TrusteeWithdrawVote) private trusteeWithdrawVotes;
/*================= STAGE =====================*/
constructor(uint _freeDaysAfterToJoin, uint _percentPassVote) {
expireTimeFreeJoin = block.timestamp + _freeDaysAfterToJoin * 1 days;
percentPassVote = _percentPassVote;
}
function setExpireFreeJoin() public {
expireTimeFreeJoin = block.timestamp;
}
/* ADD MEMBER */
function joinInGroup(string memory _name) public {
address addressSender = msg.sender;
require(!isJoined(addressSender), "You already join the group");
if(block.timestamp <= expireTimeFreeJoin) {
addMember(addressSender, _name, 1);
return;
}
MemberInVote memory vote = memberInVotes[addressSender];
if(!vote.isCreated) {
createVoteNewMemberJoin(addressSender, _name, 1);
}
}
function voteMemberIn(address _voteKey, bool _isAgree) public {
require(isJoined(msg.sender), "You are not join the group");
MemberInVote storage vote = memberInVotes[_voteKey];
require(vote.isCreated, "The voteKey is not existed.");
require(!vote.isDone, "The voteKey is done.");
Member memory member = members[msg.sender];
if(_isAgree) {
vote.totalAgree += member.piority;
}
vote.totalPiorityVoted += member.piority;
// check vote is agree
if(isAgreeMemberJoin(vote)) {
vote.isDone = true;
addMember(_voteKey, vote.joinerName, vote.joinerPiority);
emit MemberJoinGroupSuccess(_voteKey);
return;
}
// If vote is dissagree, check is vote done?
if(isVoteMemberIsDone(vote)) {
vote.isDone = true;
emit MemberJoinGroupFail(_voteKey);
}
}
/* ADD MEMBER */
/* REMOVE MEMBER */
function createVoteRemoveMember(address _removerAddress) public {
require(isJoined(msg.sender), "You are not already join the group");
require(isJoined(_removerAddress), "Remover are not already join the group");
require(msg.sender != _removerAddress, "You can not create vote remove your self");
MemberOutVote storage vote = memberOutVotes[_removerAddress];
if (!vote.isCreated || vote.isDone) {
vote.isCreated = true;
vote.isDone = false;
vote.totalPiorityVoted = 0;
vote.totalAgree = 0;
emit CreateVoteRemoveMember(_removerAddress);
}
}
function voteRemoveMember(address _voteKey, bool _isAgree) public {
require(isJoined(msg.sender), "You are not already join the group");
require(msg.sender != _voteKey, "You can note vote remove your self");
MemberOutVote storage vote = memberOutVotes[_voteKey];
require(vote.isCreated, "The voteKey is not existed.");
require(!vote.isDone, "The voteKey is done.");
Member memory member = members[msg.sender];
if(_isAgree) {
vote.totalAgree += member.piority;
}
vote.totalPiorityVoted += member.piority;
// check vote is agree
if(isAgreeRemoveMember(_voteKey, vote)) {
vote.isDone = true;
removeMember(_voteKey);
emit RemoveMemberSuccess(_voteKey);
return;
}
// If vote is dissagree, check is vote done?
if(isVoteRemoveMemberDone(_voteKey, vote)) {
vote.isDone = true;
emit DissagreeRemoveMember(_voteKey);
}
}
/* REMOVE MEMBER */
/* STACK MONEY */
function stack() payable public {
require(isJoined(msg.sender), "You are not already join the group");
}
/* STACK MONEY */
/* WITHDRAW MONEY */
function createVoteWithDraw(uint _amount, string memory _withdrawReason) public {
require(isJoined(msg.sender), "You are not already join the group");
require(address(this).balance - amountLock >= _amount, "Can not withdraw greater than total money of smartcontract");
require(bytes(_withdrawReason).length != 0, "Reason could not be blank");
uint withdrawKey = block.timestamp;
WithdrawVote storage vote = withdrawVotes[withdrawKey];
vote.amount = _amount;
vote.reason = _withdrawReason;
vote.totalAgree = 0;
vote.isDone = false;
vote.isCreated = true;
vote.totalPiorityVoted = 0;
amountLock += _amount;
emit CreateWithdrawVote(withdrawKey, _amount, _withdrawReason);
}
function voteWithdraw(uint _voteKey, bool _isAgree) public {
require(isJoined(msg.sender), "You are not already join the group");
WithdrawVote storage vote = withdrawVotes[_voteKey];
require(vote.isCreated, "The voteKey is not existed.");
require(!vote.isDone, "The voteKey is done.");
Member memory member = members[msg.sender];
if(_isAgree) {
vote.totalAgree += member.piority;
}
vote.totalPiorityVoted += member.piority;
// check vote is agree
if(isAgreeWithdraw(vote)) {
vote.isDone = true;
emit AgreeWithdraw(_voteKey, vote.amount, vote.reason);
createTrusteeWithdrawVote(vote);
return;
}
// If vote is dissagree, check is vote done?
if(isVoteWithdrawDone(vote)) {
vote.isDone = true;
emit DissagreeWithdraw(_voteKey, vote.amount, vote.reason);
}
}
function createTrusteeWithdrawVote(WithdrawVote memory _withdrawVote) private {
uint key = block.timestamp;
TrusteeWithdrawVote storage vote = trusteeWithdrawVotes[key];
vote.isCreated = true;
vote.withdrawVote = _withdrawVote;
emit CreateVoteTrusteeWithdraw(key, _withdrawVote.amount, _withdrawVote.reason);
}
function voteTrusteeWithdraw(uint _key, address _trusteeAddress) public {
require (isJoined(msg.sender), "You are not already join the group");
require (isJoined(_trusteeAddress), "trustee is not join the group");
TrusteeWithdrawVote storage vote = trusteeWithdrawVotes[_key];
require(vote.isCreated, "Vote is not exist");
require(!vote.isDone, "Vote is done");
Member memory member = members[msg.sender];
uint voteCount = vote.trusteeVoteds[_trusteeAddress];
if (voteCount == 0) {
vote.trusteeVoteds[_trusteeAddress] = 1;
} else {
vote.trusteeVoteds[_trusteeAddress] = ++voteCount;
}
vote.totalPiorityVoted += member.piority;
if(isVoteTrusteeWithdrawDone(vote)) {
address trusteeAddress = getMostTrsuteeAddress(vote);
vote.trusteeChoosen = trusteeAddress;
emit VoteTrusteeWithdrawDone(_key, trusteeAddress, vote.withdrawVote.amount, vote.withdrawVote.reason);
}
}
function withdraw(uint _trusteeWithdrawVotekey) public {
require (isJoined(msg.sender), "You are not already join the group");
TrusteeWithdrawVote storage vote = trusteeWithdrawVotes[_trusteeWithdrawVotekey];
require(vote.isDone, "Vote is not done");
require(vote.trusteeChoosen == msg.sender, "you are not a trustee");
require(!vote.isWithdraw, "Money is withdraw");
(bool sent, ) = msg.sender.call{value: vote.withdrawVote.amount}("");
require(sent, "Failed to withdraw");
}
/* WITHDRAW MONEY */
function getMostTrsuteeAddress(TrusteeWithdrawVote storage _vote) private view returns(address) {
uint trusteeMaxVote = 0;
address trusteeAddress;
uint trusteeVote;
for (uint index = 0; index < _vote.trusteesAddress.length; index ++) {
trusteeVote = _vote.trusteeVoteds[_vote.trusteesAddress[index]];
if(trusteeVote > trusteeMaxVote) {
trusteeMaxVote = trusteeVote;
trusteeAddress = _vote.trusteesAddress[index];
}
}
return trusteeAddress;
}
function isVoteTrusteeWithdrawDone(TrusteeWithdrawVote storage _vote) private view returns(bool) {
return _vote.totalPiorityVoted >= totalMemberPiority;
}
function isVoteWithdrawDone(WithdrawVote memory _vote) private view returns(bool) {
return _vote.totalPiorityVoted >= totalMemberPiority;
}
function isAgreeWithdraw(WithdrawVote memory _vote) private view returns(bool) {
uint agreePercent = _vote.totalAgree * 100 / totalMemberPiority;
return agreePercent >= percentPassVote;
}
function isVoteRemoveMemberDone(address _address, MemberOutVote memory _vote) private view returns(bool) {
return _vote.totalPiorityVoted >= totalMemberPiority - members[_address].piority;
}
function isAgreeRemoveMember(address _address, MemberOutVote memory _vote) private view returns(bool) {
uint agreePercent = _vote.totalAgree * 100 / (totalMemberPiority - members[_address].piority);
return agreePercent >= percentPassVote;
}
function removeMember(address _address) private {
delete members[_address];
}
function isVoteMemberIsDone(MemberInVote memory _vote) private view returns(bool) {
return _vote.totalPiorityVoted >= totalMemberPiority;
}
function isAgreeMemberJoin(MemberInVote memory _vote) private view returns(bool) {
uint agreePercent = _vote.totalAgree * 100 / totalMemberPiority;
return agreePercent >= percentPassVote;
}
function addMember(address _address, string memory _name, uint _piority) private {
Member storage newMember = members[_address];
newMember.name = _name;
newMember.piority = _piority;
totalMemberPiority += newMember.piority;
totalMember ++;
}
function createVoteNewMemberJoin(address _address, string memory _name, uint _piority) private {
require(!isJoined(_address), "The address already join the group");
MemberInVote storage vote = memberInVotes[_address];
vote.totalAgree = 0;
vote.isCreated = true;
vote.isDone = false;
vote.joinerName = _name;
vote.joinerPiority = _piority;
emit CreateVoteNewMemberJoin(_address);
}
function isJoined(address _address) private view returns(bool) {
return bytes(members[_address].name).length != 0;
}
/* Events */
event CreateVoteNewMemberJoin(address _newMemberAddress);
event MemberJoinGroupSuccess(address _newMemberAddress);
event MemberJoinGroupFail(address _newMemberAddress);
event CreateVoteRemoveMember(address _removerAddress);
event RemoveMemberSuccess(address _removerAddress);
event DissagreeRemoveMember(address _removerAddress);
event CreateWithdrawVote(uint _key, uint _amount, string _withdrawReason);
event DissagreeWithdraw(uint _key, uint _amount, string _withdrawReason);
event AgreeWithdraw(uint _key, uint _amount, string _withdrawReason);
event CreateVoteTrusteeWithdraw(uint _key, uint _amount, string _withdrawReason);
event VoteTrusteeWithdrawDone(uint _key, address _trusteeAddress, uint _amount, string _withdrawReason);
/* Events */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment