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 ); }
public void SubmitProposal( Address applicant, ulong tokenTribute, ulong sharesRequested, string details) { AssertOnlyDelegate(); Assert(applicant != Address.Zero, "Moloch::submitProposal - applicant cannot be 0"); // Make sure we won't run into overflows when doing calculations with shares. // Note that totalShares + totalSharesRequested + sharesRequested is an upper bound // on the number of shares that can exist until this proposal has been processed. Assert(TotalShares.Add(TotalSharesRequested).Add(sharesRequested) <= MAX_NUMBER_OF_SHARES, "Moloch::submitProposal - too many shares requested"); TotalSharesRequested = TotalSharesRequested.Add(sharesRequested); Address memberAddress = GetMemberAddressByDelegateKey(Message.Sender); // todo: correct equivalent of address(this)? // collect proposal deposit from proposer and store it in the Moloch until the proposal is processed Assert(ApprovedStandardToken.TransferFrom(Message.Sender, this.Address, ProposalDeposit), "Moloch::submitProposal - proposal deposit token transfer failed"); // todo: correct equivalent of address(this)? // collect tribute from applicant and store it in the Moloch until the proposal is processed Assert(ApprovedStandardToken.TransferFrom(applicant, this.Address, tokenTribute), "Moloch::submitProposal - tribute token transfer failed"); // compute startingPeriod for proposal ulong startingPeriod = Max( GetCurrentPeriod(), GetProposalQueueLength() == 0 ? 0 : GetProposalQueue()[GetProposalQueueLength().Sub(1)].StartingPeriod ).Add(1); // create proposal ... Proposal proposal = new Proposal() { Proposer = memberAddress, Applicant = applicant, SharesRequested = sharesRequested, StartingPeriod = startingPeriod, YesVotes = 0, NoVotes = 0, Processed = false, DidPass = false, Aborted = false, TokenTribute = tokenTribute, Details = details, MaxTotalSharesAtYesVote = 0 }; // ... and append it to the queue var proposalQueue = GetProposalQueue(); Array.Resize(ref proposalQueue, proposalQueue.Length + 1); proposalQueue[proposalQueue.GetUpperBound(0)] = proposal; SetProposalQueue(proposalQueue); ulong proposalIndex = ((ulong)proposalQueue.Length).Sub(1); LogSubmitProposal(proposalIndex, Message.Sender, memberAddress, applicant, tokenTribute, sharesRequested); }