Created
April 7, 2023 18:07
-
-
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=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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