public void Ragequit(ulong sharesToBurn) { AssertOnlyMember(); ulong initialTotalShares = TotalShares; Member member = GetMember(Message.Sender); Assert(member.Shares >= sharesToBurn, "Moloch::ragequit - insufficient shares"); Assert(canRagequit(member.HighestIndexYesVote), "Moloch::ragequit - cant ragequit until highest index proposal member voted YES on is processed"); // burn shares member.Shares = member.Shares.Sub(sharesToBurn); TotalShares = TotalShares.Sub(sharesToBurn); SetMember(Message.Sender, member); // instruct guildBank to transfer fair share of tokens to the ragequitter Assert( GuildBank.Withdraw(Message.Sender, sharesToBurn, initialTotalShares), "Moloch::ragequit - withdrawal of tokens from guildBank failed" ); LogRagequit(Message.Sender, sharesToBurn); }
public Moloch( ISmartContractState state, Address summoner, Address _approvedToken, ulong _periodDuration, ulong _votingPeriodLength, ulong _gracePeriodLength, ulong _abortWindow, ulong _proposalDeposit, ulong _dilutionBound, ulong _processingReward, Address approvedTokenAddress, IStandardToken approvedStandardToken ) : base(state) { Assert(summoner != Address.Zero, "Moloch::constructor - summoner cannot be 0"); Assert(_approvedToken != Address.Zero, "Moloch::constructor - _approvedToken cannot be 0"); Assert(_periodDuration > 0, "Moloch::constructor - _periodDuration cannot be 0"); Assert(_votingPeriodLength > 0, "Moloch::constructor - _votingPeriodLength cannot be 0"); Assert(_votingPeriodLength <= MAX_VOTING_PERIOD_LENGTH, "Moloch::constructor - _votingPeriodLength exceeds limit"); Assert(_gracePeriodLength <= MAX_GRACE_PERIOD_LENGTH, "Moloch::constructor - _gracePeriodLength exceeds limit"); Assert(_abortWindow > 0, "Moloch::constructor - _abortWindow cannot be 0"); Assert(_abortWindow <= _votingPeriodLength, "Moloch::constructor - _abortWindow must be smaller than or equal to _votingPeriodLength"); Assert(_dilutionBound > 0, "Moloch::constructor - _dilutionBound cannot be 0"); Assert(_dilutionBound <= MAX_DILUTION_BOUND, "Moloch::constructor - _dilutionBound exceeds limit"); Assert(_proposalDeposit >= _processingReward, "Moloch::constructor - _proposalDeposit cannot be smaller than _processingReward"); // todo: how to wrap calls from/to? ApprovedTokenAddress = approvedTokenAddress; ApprovedStandardToken = approvedStandardToken; // todo: how to start a new guildbank contract as well? GuildBank = new GuildBank(state, approvedTokenAddress, approvedStandardToken); PeriodDuration = _periodDuration; VotingPeriodLength = _votingPeriodLength; GracePeriodLength = _gracePeriodLength; AbortWindow = _abortWindow; ProposalDeposit = _proposalDeposit; DilutionBound = _dilutionBound; ProcessingReward = _processingReward; // todo: summoningTime = now; // now operator/call missing in stratis? SummoningTime = DateTime.UtcNow.Ticks; SetMember(summoner, new Member() { DelegateKey = summoner, Shares = 1, Exists = true, HighestIndexYesVote = 0 }); SetMemberAddressByDelegateKey(summoner, summoner); TotalShares = 1; SetProposalQueue(new Proposal[0]); LogSummonComplete(summoner, 1); }
public void ProcessProposal(ulong proposalIndex) { var proposalQueue = GetProposalQueue(); Assert(proposalIndex < (uint)proposalQueue.Length, "Moloch::processProposal - proposal does not exist"); Proposal proposal = proposalQueue[proposalIndex]; Assert(GetCurrentPeriod() >= proposal.StartingPeriod.Add(VotingPeriodLength).Add(GracePeriodLength), "Moloch::processProposal - proposal is not ready to be processed"); Assert(proposal.Processed == false, "Moloch::processProposal - proposal has already been processed"); Assert(proposalIndex == 0 || proposalQueue[proposalIndex.Sub(1)].Processed, "Moloch::processProposal - previous proposal must be processed"); proposal.Processed = true; TotalSharesRequested = TotalSharesRequested.Sub(proposal.SharesRequested); bool didPass = proposal.YesVotes > proposal.NoVotes; // Make the proposal fail if the dilutionBound is exceeded if (TotalShares.Mul(DilutionBound) < proposal.MaxTotalSharesAtYesVote) { didPass = false; } // PROPOSAL PASSED if (didPass && !proposal.Aborted) { proposal.DidPass = true; // todo: null check on many of the serialization getters and setters? // if the applicant is already a member, add to their existing shares if (GetMember(proposal.Applicant).Exists) { var applicant = GetMember(proposal.Applicant); applicant.Shares = applicant.Shares.Add(proposal.SharesRequested); SetMember(proposal.Applicant, applicant); // the applicant is a new member, create a new record for them } else { // if the applicant address is already taken by a member's delegateKey, reset it to their member address var delegateAddress = GetMemberAddressByDelegateKey(proposal.Applicant); var applicant = GetMember(delegateAddress); if (applicant.Exists) { Address memberToOverride = delegateAddress; SetMemberAddressByDelegateKey(memberToOverride, memberToOverride); var member = GetMember(memberToOverride); member.DelegateKey = memberToOverride; SetMember(memberToOverride, member); } // use applicant address as delegateKey by default SetMember(proposal.Applicant, new Member() { DelegateKey = proposal.Applicant, Shares = proposal.SharesRequested, Exists = true, HighestIndexYesVote = 0 }); SetMemberAddressByDelegateKey(proposal.Applicant, proposal.Applicant); } // mint new shares TotalShares = TotalShares.Add(proposal.SharesRequested); // transfer tokens to guild bank Assert( ApprovedStandardToken.TransferTo(GuildBank.GetAddress(), proposal.TokenTribute), "Moloch::processProposal - token transfer to guild bank failed" ); // PROPOSAL FAILED OR ABORTED } else { // return all tokens to the applicant Assert( ApprovedStandardToken.TransferTo(proposal.Applicant, proposal.TokenTribute), "Moloch::processProposal - failing vote token transfer failed" ); } // send msg.sender the processingReward Assert( ApprovedStandardToken.TransferTo(Message.Sender, ProcessingReward), "Moloch::processProposal - failed to send processing reward to msg.sender" ); // return deposit to proposer (subtract processing reward) Assert( ApprovedStandardToken.TransferTo(proposal.Proposer, ProposalDeposit.Sub(ProcessingReward)), "Moloch::processProposal - failed to return proposal deposit to proposer" ); LogProcessProposal( proposalIndex, proposal.Applicant, proposal.Proposer, proposal.TokenTribute, proposal.SharesRequested, didPass ); }