Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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
                );
        }