diff --git a/CHANGELOG.md b/CHANGELOG.md index 239c4e4..44f50c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ This format is based on [Keep A Changelog](https://keepachangelog.com/en/1.0.0). ### Modified +- Support voting/retracting votes with multiple stakes. + + NOTE: Due to the fact that the order of stake locks is undefined, voting to + multiple proposals in a single tx is disallowed. + + Included by [#186](https://github.com/Liqwid-Labs/agora/pull/186) + - Fix a bug that allows an attacker to send two or more GATs to an effect in the winning effect group. Fixed by [#181](https://github.com/Liqwid-Labs/agora/pull/181) diff --git a/agora-specs/Property/Governor.hs b/agora-specs/Property/Governor.hs index 5226637..9023a35 100644 --- a/agora-specs/Property/Governor.hs +++ b/agora-specs/Property/Governor.hs @@ -63,6 +63,7 @@ import Test.Tasty.QuickCheck ( data GovernorDatumCases = ExecuteLE0 | CreateLE0 + | ToVotingLE0 | VoteLE0 | Correct deriving stock (Eq, Show) @@ -88,9 +89,10 @@ governorDatumValidProperty = classifiedPropertyNative gen (const []) expected classifier pisGovernorDatumValid where classifier :: GovernorDatum -> GovernorDatumCases - classifier ((.proposalThresholds) -> ProposalThresholds e c v) + classifier ((.proposalThresholds) -> ProposalThresholds e c tv v) | e < 0 = ExecuteLE0 | c < 0 = CreateLE0 + | tv < 0 = ToVotingLE0 | v < 0 = VoteLE0 | otherwise = Correct @@ -110,24 +112,27 @@ governorDatumValidProperty = let validGT = taggedInteger (0, 1000000000) execute <- validGT create <- validGT + toVoting <- validGT vote <- validGT le0 <- taggedInteger (-1000, -1) case c of ExecuteLE0 -> -- execute < 0 - return $ ProposalThresholds le0 create vote + return $ ProposalThresholds le0 create toVoting vote CreateLE0 -> -- c < 0 - return $ ProposalThresholds execute le0 vote + return $ ProposalThresholds execute le0 toVoting vote + ToVotingLE0 -> + return $ ProposalThresholds execute create le0 vote VoteLE0 -> -- vote < 0 - return $ ProposalThresholds execute create le0 + return $ ProposalThresholds execute create toVoting le0 Correct -> do -- c <= vote < execute nv <- taggedInteger (0, untag execute - 1) nc <- taggedInteger (0, untag nv) - return $ ProposalThresholds execute nc nv + return $ ProposalThresholds execute nc toVoting nv data GovernorPolicyCases = ReferenceUTXONotSpent diff --git a/agora-specs/Sample/Effect/GovernorMutation.hs b/agora-specs/Sample/Effect/GovernorMutation.hs index 076584e..c88ad4a 100644 --- a/agora-specs/Sample/Effect/GovernorMutation.hs +++ b/agora-specs/Sample/Effect/GovernorMutation.hs @@ -195,7 +195,7 @@ invalidNewGovernorDatum = GovernorDatum { proposalThresholds = def - { vote = Tagged (-1) + { toVoting = Tagged (-1) } , nextProposalId = ProposalId 42 , proposalTimings = def diff --git a/agora-specs/Sample/Governor/Initialize.hs b/agora-specs/Sample/Governor/Initialize.hs index a58d862..63b56cf 100644 --- a/agora-specs/Sample/Governor/Initialize.hs +++ b/agora-specs/Sample/Governor/Initialize.hs @@ -93,7 +93,7 @@ validGovernorOutputDatum = } invalidProposalThresholds :: ProposalThresholds -invalidProposalThresholds = ProposalThresholds (-1) (-1) (-1) +invalidProposalThresholds = ProposalThresholds (-1) (-1) (-1) (-1) invalidMaxTimeRangeWidth :: MaxTimeRangeWidth invalidMaxTimeRangeWidth = MaxTimeRangeWidth 0 diff --git a/agora-specs/Sample/Governor/Mutate.hs b/agora-specs/Sample/Governor/Mutate.hs index e4ba560..fffb485 100644 --- a/agora-specs/Sample/Governor/Mutate.hs +++ b/agora-specs/Sample/Governor/Mutate.hs @@ -120,6 +120,7 @@ mkGovernorOutputDatum ValueInvalid = ProposalThresholds { execute = -1 , create = -1 + , toVoting = -1 , vote = -1 } in Just $ diff --git a/agora-specs/Sample/Proposal/Advance.hs b/agora-specs/Sample/Proposal/Advance.hs index 93c254f..5ae15f2 100644 --- a/agora-specs/Sample/Proposal/Advance.hs +++ b/agora-specs/Sample/Proposal/Advance.hs @@ -679,7 +679,7 @@ getNextState = \case -- | Calculate the number of GTs per stake in order to exceed the minimum limit. compPerStakeGTsForDraft :: NumStake -> Integer compPerStakeGTsForDraft nCosigners = - untag (def :: ProposalThresholds).vote + untag (def :: ProposalThresholds).toVoting `div` fromIntegral nCosigners + 1 dummyDatum :: () @@ -944,7 +944,7 @@ mkInsufficientCosignsBundle nCosigners nEffects = } where insuffcientPerStakeGTs = - untag (def :: ProposalThresholds).vote + untag (def :: ProposalThresholds).toVoting `div` fromIntegral nCosigners - 1 template = mkValidToNextStateBundle nCosigners nEffects False Draft diff --git a/agora-specs/Sample/Proposal/Unlock.hs b/agora-specs/Sample/Proposal/Unlock.hs new file mode 100644 index 0000000..8eca632 --- /dev/null +++ b/agora-specs/Sample/Proposal/Unlock.hs @@ -0,0 +1,541 @@ +{- | +Module : Sample.Proposal.UnlockStake +Maintainer : connor@mlabs.city +Description: Generate sample data for testing the functionalities of unlocking stake and retracting votes + +Sample and utilities for testing the functionalities of unlocking stake and retracting votes +-} +module Sample.Proposal.Unlock ( + ParameterBundle (..), + StakeRole (..), + TimeRange (..), + SignedBy (..), + TransactionParameters (..), + ProposalParameters (..), + StakeParameters (..), + Validity (..), + unlock, + mkTestTree, + mkValidVoterRetractVotes, + mkValidDelegateeRetractVotes, + mkValidVoterCreatorRetractVotes, + mkValidCreatorRemoveLock, + mkValidVoterRemoveLockAfterVoting, + mkRetractVotesWhileNotVoting, + mkUnockIrrelevantStakes, + mkRemoveCreatorLockBeforeFinished, + mkCreatorRetractVotes, + mkChangeOutputStakeValue, +) where + +-------------------------------------------------------------------------------- + +import Agora.Governor (Governor (..)) +import Agora.Proposal ( + ProposalDatum (..), + ProposalEffectGroup, + ProposalId (..), + ProposalRedeemer (Unlock), + ProposalStatus (..), + ProposalVotes (..), + ResultTag (..), + ) +import Agora.Proposal.Time (ProposalStartingTime (ProposalStartingTime), ProposalTimingConfig (..)) +import Agora.Scripts (AgoraScripts (..)) +import Agora.Stake ( + ProposalLock (..), + StakeDatum (..), + StakeRedeemer (RetractVotes), + ) +import Data.Default.Class (Default (def)) +import Data.Map.Strict qualified as StrictMap +import Data.Tagged (Tagged (Tagged), untag) +import Plutarch.Context ( + input, + normalizeValue, + output, + script, + signedWith, + timeRange, + txId, + withDatum, + withRedeemer, + withRef, + withValue, + ) +import Plutarch.SafeMoney (Discrete (Discrete)) +import PlutusLedgerApi.V1.Value qualified as Value +import PlutusLedgerApi.V2 ( + Credential (PubKeyCredential), + PubKeyHash, + TxOutRef (..), + ) +import Sample.Proposal.Shared (stakeTxRef) +import Sample.Shared ( + agoraScripts, + governor, + minAda, + proposalPolicySymbol, + proposalValidatorHash, + stakeAssetClass, + stakeValidatorHash, + ) +import Test.Specification (SpecificationTree, group, testValidator) +import Test.Util (CombinableBuilder, closedBoundedInterval, mkSpending, pubKeyHashes) + +-------------------------------------------------------------------------------- + +votesTemplate :: ProposalVotes +votesTemplate = + ProposalVotes $ + StrictMap.fromList + [ (ResultTag 0, 0) + , (ResultTag 1, 0) + ] + +-- | Create empty effects for every result tag given the votes. +emptyEffectFor :: + ProposalVotes -> + StrictMap.Map ResultTag ProposalEffectGroup +emptyEffectFor (ProposalVotes vs) = + StrictMap.fromList $ + map (,StrictMap.empty) (StrictMap.keys vs) + +-- | The default vote option that will be used by functions in this module. +defVoteFor :: ResultTag +defVoteFor = ResultTag 0 + +-- | The default number of GTs the stake will have. +defStakedGTs :: Integer +defStakedGTs = 100000 + +alteredStakedGTs :: Integer +alteredStakedGTs = 100 + +-- | Default owner of the stakes. +defOwner :: PubKeyHash +defOwner = pubKeyHashes !! 1 + +defDelegatee :: PubKeyHash +defDelegatee = pubKeyHashes !! 2 + +defUnknown :: PubKeyHash +defUnknown = pubKeyHashes !! 3 + +defProposalId :: ProposalId +defProposalId = ProposalId 0 + +defStartingTime :: ProposalStartingTime +defStartingTime = ProposalStartingTime 0 + +-------------------------------------------------------------------------------- + +data ParameterBundle = ParameterBundle + { proposalParameters :: ProposalParameters + , stakeParameters :: StakeParameters + , transactionParameters :: TransactionParameters + } + +data SignedBy = Owner | Delegatee | Unknown + +data TimeRange = WhileVoting | AfterVoting + +data TransactionParameters = TransactionParameters + { signedBy :: SignedBy + , timeRange :: TimeRange + } + +data ProposalParameters = ProposalParameters + { proposalStatus :: ProposalStatus + , retractVotes :: Bool + } + +-- | How a stake has been used on a particular proposal. +data StakeRole + = -- | The stake was spent to vote for a paraticular option. + Voter + | -- | The stake was used to create the proposal. + Creator + | -- | The stake was used to both create and vote for the proposal. + Both + | -- | The stake has nothing to do with the proposal. + Irrelevant + deriving stock (Bounded, Enum, Show) + +data StakeParameters = StakeParameters + { numStakes :: Integer + , stakeRole :: StakeRole + , removeVoterLock :: Bool + , removeCreatorLock :: Bool + , alterOutputValue :: Bool + } + +data Validity = Validity + { forProposalValidator :: Bool + , forStakeValidator :: Bool + } + +-------------------------------------------------------------------------------- + +mkStakeRef :: Integer -> TxOutRef +mkStakeRef = TxOutRef stakeTxRef + +stakeRedeemer :: StakeRedeemer +stakeRedeemer = RetractVotes + +mkStakeInputDatum :: StakeParameters -> StakeDatum +mkStakeInputDatum ps = + StakeDatum + { stakedAmount = Discrete $ Tagged defStakedGTs + , owner = PubKeyCredential defOwner + , delegatedTo = Just $ PubKeyCredential defDelegatee + , lockedBy = stakeLocks + } + where + stakeLocks = mkStakeLocks' ps.stakeRole + + mkStakeLocks' Voter = [Voted defProposalId defVoteFor] + mkStakeLocks' Creator = [Created defProposalId] + mkStakeLocks' Both = mkStakeLocks' Voter <> mkStakeLocks' Creator + mkStakeLocks' Irrelevant = + let ProposalId pid = defProposalId + ResultTag vid = defVoteFor + in [ Voted (ProposalId $ pid + 1) (ResultTag $ vid + 1) + , Created (ProposalId $ pid + 1) + ] + +-------------------------------------------------------------------------------- + +proposalRef :: TxOutRef +proposalRef = TxOutRef stakeTxRef 0 + +proposalRedeemer :: ProposalRedeemer +proposalRedeemer = Unlock + +mkProposalInputDatum :: + StakeParameters -> + ProposalParameters -> + ProposalDatum +mkProposalInputDatum sps pps = + ProposalDatum + { proposalId = defProposalId + , effects = emptyEffectFor votesTemplate + , status = pps.proposalStatus + , cosigners = [PubKeyCredential $ head pubKeyHashes] + , thresholds = def + , votes = updatVotes votesTemplate + , timingConfig = def + , startingTime = defStartingTime + } + where + updatVotes (ProposalVotes vt) = + ProposalVotes $ + StrictMap.adjust + (+ sps.numStakes * defStakedGTs) + defVoteFor + vt + +-------------------------------------------------------------------------------- + +unlock :: forall b. CombinableBuilder b => ParameterBundle -> b +unlock ps = builder + where + pst = Value.singleton proposalPolicySymbol "" 1 + + proposalInputDatum = + mkProposalInputDatum + ps.stakeParameters + ps.proposalParameters + + proposalOutputDatum = + if ps.proposalParameters.retractVotes + then proposalInputDatum {votes = votesTemplate} + else proposalInputDatum + + proposalValue = normalizeValue $ pst <> minAda + + proposalBuilder :: b + proposalBuilder = + mconcat + [ input $ + mconcat + [ script proposalValidatorHash + , withValue proposalValue + , withDatum proposalInputDatum + , withRef proposalRef + , withRedeemer proposalRedeemer + ] + , output $ + mconcat + [ script proposalValidatorHash + , withValue proposalValue + , withDatum proposalOutputDatum + ] + ] + + --- + + sst = Value.assetClassValue stakeAssetClass 1 + + stakeInputDatum = mkStakeInputDatum ps.stakeParameters + + removeLocks v c = + filter $ + not + . ( \case + Created pid -> c && pid == defProposalId + Voted pid _ -> v && pid == defProposalId + ) + + stakeOutputDatum = + stakeInputDatum + { lockedBy = + removeLocks + ps.stakeParameters.removeVoterLock + ps.stakeParameters.removeCreatorLock + stakeInputDatum.lockedBy + } + + mkStakeValue gt = + normalizeValue $ + mconcat + [ minAda + , sst + , Value.assetClassValue + (untag governor.gtClassRef) + gt + ] + + stakeInputValue = mkStakeValue defStakedGTs + + stakeOutputValue = + mkStakeValue $ + if ps.stakeParameters.alterOutputValue + then alteredStakedGTs + else defStakedGTs + + stakeBuilder :: b + stakeBuilder = + foldMap + ( \i -> + mconcat + [ input $ + mconcat + [ script stakeValidatorHash + , withValue stakeInputValue + , withDatum stakeInputDatum + , withRef $ mkStakeRef i + ] + , output $ + mconcat + [ script stakeValidatorHash + , withValue stakeOutputValue + , withDatum stakeOutputDatum + ] + ] + ) + [1 .. ps.stakeParameters.numStakes] + + --- + + time = case ps.transactionParameters.timeRange of + WhileVoting -> + closedBoundedInterval + ((def :: ProposalTimingConfig).draftTime + 1) + ((def :: ProposalTimingConfig).votingTime - 1) + AfterVoting -> + closedBoundedInterval + ((def :: ProposalTimingConfig).votingTime + 1) + ((def :: ProposalTimingConfig).lockingTime - 1) + + sig = case ps.transactionParameters.signedBy of + Unknown -> defUnknown + Owner -> defOwner + Delegatee -> defDelegatee + + --- + + builder = + mconcat + [ txId "388bc0b897b3dadcd479da4c88291de4113a50b72ddbed001faf7fc03f11bc52" + , proposalBuilder + , stakeBuilder + , signedWith sig + , timeRange time + ] + +-------------------------------------------------------------------------------- + +{- | Create a test tree that runs both the stake validator and the proposal + validator. +-} +mkTestTree :: String -> ParameterBundle -> Validity -> SpecificationTree +mkTestTree name ps val = group name [stake, proposal] + where + spend = mkSpending unlock ps + + stake = + testValidator + val.forStakeValidator + "stake" + agoraScripts.compiledStakeValidator + (mkStakeInputDatum ps.stakeParameters) + stakeRedeemer + (spend $ mkStakeRef 1) + + proposal = + testValidator + val.forProposalValidator + "proposal" + agoraScripts.compiledProposalValidator + (mkProposalInputDatum ps.stakeParameters ps.proposalParameters) + proposalRedeemer + (spend proposalRef) + +-------------------------------------------------------------------------------- + +mkValidVoterRetractVotes :: Integer -> ParameterBundle +mkValidVoterRetractVotes i = + ParameterBundle + { proposalParameters = + ProposalParameters + { proposalStatus = VotingReady + , retractVotes = True + } + , stakeParameters = + StakeParameters + { numStakes = i + , stakeRole = Voter + , removeVoterLock = True + , removeCreatorLock = False + , alterOutputValue = False + } + , transactionParameters = + TransactionParameters + { signedBy = Owner + , timeRange = + WhileVoting + } + } + +mkValidDelegateeRetractVotes :: Integer -> ParameterBundle +mkValidDelegateeRetractVotes i = + let template = mkValidVoterRetractVotes i + in template + { transactionParameters = + template.transactionParameters + { signedBy = Delegatee + } + } + +mkValidVoterCreatorRetractVotes :: Integer -> ParameterBundle +mkValidVoterCreatorRetractVotes i = + let template = mkValidVoterRetractVotes i + in template + { stakeParameters = + template.stakeParameters + { stakeRole = Both + } + } + +mkValidCreatorRemoveLock :: Integer -> ParameterBundle +mkValidCreatorRemoveLock i = + let template = mkValidVoterRetractVotes i + in template + { proposalParameters = + template.proposalParameters + { proposalStatus = Finished + , retractVotes = False + } + , stakeParameters = + template.stakeParameters + { stakeRole = Creator + , removeCreatorLock = True + } + , transactionParameters = + template.transactionParameters + { timeRange = AfterVoting + } + } + +mkValidVoterRemoveLockAfterVoting :: Integer -> ParameterBundle +mkValidVoterRemoveLockAfterVoting i = + let template = mkValidVoterRetractVotes i + in template + { proposalParameters = + template.proposalParameters + { proposalStatus = Finished + , retractVotes = False + } + , transactionParameters = + template.transactionParameters + { timeRange = AfterVoting + } + } + +mkRetractVotesWhileNotVoting :: Integer -> [ParameterBundle] +mkRetractVotesWhileNotVoting i = + let template = mkValidVoterRetractVotes i + in map + ( \s -> + template + { proposalParameters = + template.proposalParameters + { proposalStatus = s + } + } + ) + [Draft, Locked, Finished] + +mkUnockIrrelevantStakes :: Integer -> ParameterBundle +mkUnockIrrelevantStakes i = + let template = mkValidVoterRetractVotes i + in template + { stakeParameters = + template.stakeParameters + { stakeRole = Irrelevant + , removeCreatorLock = True + } + } + +mkRemoveCreatorLockBeforeFinished :: Integer -> [ParameterBundle] +mkRemoveCreatorLockBeforeFinished i = + let template = mkValidCreatorRemoveLock i + in map + ( \s -> + template + { proposalParameters = + template.proposalParameters + { proposalStatus = s + } + } + ) + [Draft, VotingReady, Locked] + +mkCreatorRetractVotes :: Integer -> ParameterBundle +mkCreatorRetractVotes i = + let template = mkValidVoterRetractVotes i + in template + { proposalParameters = + template.proposalParameters + { proposalStatus = VotingReady + } + , stakeParameters = + template.stakeParameters + { stakeRole = Creator + } + , transactionParameters = + template.transactionParameters + { timeRange = WhileVoting + } + } + +mkChangeOutputStakeValue :: Integer -> ParameterBundle +mkChangeOutputStakeValue i = + let template = mkValidVoterRetractVotes i + in template + { stakeParameters = + template.stakeParameters + { alterOutputValue = True + } + } diff --git a/agora-specs/Sample/Proposal/UnlockStake.hs b/agora-specs/Sample/Proposal/UnlockStake.hs deleted file mode 100644 index 510de7c..0000000 --- a/agora-specs/Sample/Proposal/UnlockStake.hs +++ /dev/null @@ -1,559 +0,0 @@ -{- | -Module : Sample.Proposal.UnlockStake -Maintainer : connor@mlabs.city -Description: Generate sample data for testing the functionalities of unlocking stake and retracting votes - -Sample and utilities for testing the functionalities of unlocking stake and retracting votes --} -module Sample.Proposal.UnlockStake ( - StakeRole (..), - Parameters (..), - unlockStake, - mkTestTree, - mkVoterRetractVotesWhileVotingParameters, - mkVoterCreatorRetractVotesWhileVotingParameters, - mkCreatorRemoveCreatorLocksWhenFinishedParameters, - mkVoterCreatorRemoveAllLocksWhenFinishedParameters, - mkVoterUnlockStakeAfterVotingParameters, - mkVoterCreatorRemoveVoteLocksWhenLockedParameters, - mkRetractVotesWhileNotVoting, - mkUnockIrrelevantStakeParameters, - mkRemoveCreatorLockBeforeFinishedParameters, - mkRetractVotesWithCreatorStakeParamaters, - mkAlterStakeParameters, -) where - --------------------------------------------------------------------------------- - -import Agora.Governor (Governor (..)) -import Agora.Proposal ( - ProposalDatum (..), - ProposalEffectGroup, - ProposalId (..), - ProposalRedeemer (Unlock), - ProposalStatus (..), - ProposalVotes (..), - ResultTag (..), - ) -import Agora.Proposal.Time (ProposalStartingTime (ProposalStartingTime)) -import Agora.SafeMoney (GTTag) -import Agora.Scripts (AgoraScripts (..)) -import Agora.Stake ( - ProposalLock (..), - StakeDatum (..), - StakeRedeemer (RetractVotes), - ) -import Data.Default.Class (Default (def)) -import Data.Map.Strict qualified as StrictMap -import Data.Tagged (untag) -import Plutarch.Context ( - input, - output, - script, - signedWith, - txId, - withDatum, - withRedeemer, - withRef, - withValue, - ) -import Plutarch.SafeMoney (Discrete) -import PlutusLedgerApi.V1.Value qualified as Value -import PlutusLedgerApi.V2 ( - Credential (PubKeyCredential), - PubKeyHash, - TxOutRef (..), - ) -import Sample.Proposal.Shared (stakeTxRef) -import Sample.Shared ( - agoraScripts, - fromDiscrete, - governor, - minAda, - proposalPolicySymbol, - proposalValidatorHash, - signer, - stakeAssetClass, - stakeValidatorHash, - ) -import Test.Specification (SpecificationTree, group, testValidator) -import Test.Util (CombinableBuilder, mkSpending, sortValue) - --------------------------------------------------------------------------------- - --- | The template "shape" that votes of proposals generated by 'mkProposalDatumPair' have. -votesTemplate :: ProposalVotes -votesTemplate = - ProposalVotes $ - StrictMap.fromList - [ (ResultTag 0, 0) - , (ResultTag 1, 0) - ] - --- | Create empty effects for every result tag given the votes. -emptyEffectFor :: - ProposalVotes -> - StrictMap.Map ResultTag ProposalEffectGroup -emptyEffectFor (ProposalVotes vs) = - StrictMap.fromList $ - map (,StrictMap.empty) (StrictMap.keys vs) - --- | The default vote option that will be used by functions in this module. -defVoteFor :: ResultTag -defVoteFor = ResultTag 0 - --- | The default number of GTs the stake will have. -defStakedGTs :: Discrete GTTag -defStakedGTs = 100000 - -{- | If 'Parameters.alterOutputStake' is set to true, the - 'StakeDatum.stakedAmount' will be set to this. --} -alteredStakedGTs :: Discrete GTTag -alteredStakedGTs = 100 - --- | Default owner of the stakes. -defOwner :: PubKeyHash -defOwner = signer - --- | How a stake has been used on a particular proposal. -data StakeRole - = -- | The stake was spent to vote for a paraticular option. - Voter - | -- | The stake was used to create the proposal. - Creator - | -- | The stake was used to both create and vote for the proposal. - Both - | -- | The stake has nothing to do with the proposal. - Irrelevant - deriving stock (Bounded, Enum, Show) - --- | Parameters for creating a 'TxOut' that unlocks a stake. -data Parameters = Parameters - { proposalCount :: Integer - -- ^ The number of proposals in the 'TxOut'. - , stakeRole :: StakeRole - -- ^ The role of the stake we're unlocking. - , retractVotes :: Bool - -- ^ Whether to retract votes or not. - , removeVoterLock :: Bool - -- ^ Remove the voter locks from the input stake. - , removeCreatorLock :: Bool - -- ^ Remove the creator locks from the input stake. - , proposalStatus :: ProposalStatus - -- ^ The state of all the proposals. - , alterOutputStake :: Bool - } - --- | Iterate over the proposal id of every proposal, given the number of proposals. -forEachProposalId :: Parameters -> (ProposalId -> a) -> [a] -forEachProposalId ps = forEachProposalId' ps.proposalCount - where - forEachProposalId' :: Integer -> (ProposalId -> a) -> [a] - forEachProposalId' 0 _ = error "zero proposal" - forEachProposalId' n f = f . ProposalId <$> [0 .. n - 1] - --- | Create locks for the input stake given the parameters. -mkInputStakeLocks :: Parameters -> [ProposalLock] -mkInputStakeLocks ps = mconcat $ forEachProposalId ps $ mkStakeLocksFor ps.stakeRole - where - mkStakeLocksFor :: StakeRole -> ProposalId -> [ProposalLock] - mkStakeLocksFor sr pid = - let voted = [Voted pid defVoteFor] - created = [Created pid] - in case sr of - Voter -> voted - Creator -> created - Both -> voted <> created - _ -> [] - --- | Create locks for the output stake by removing locks from the input locks. -mkOutputStakeLocks :: Parameters -> [ProposalLock] -mkOutputStakeLocks ps = - filter - ( \lock -> not $ case lock of - Voted _ _ -> ps.removeVoterLock - Created _ -> ps.removeCreatorLock - ) - inputLocks - where - inputLocks = mkInputStakeLocks ps - --- | Create the stake input datum given the parameters. -mkStakeInputDatum :: Parameters -> StakeDatum -mkStakeInputDatum ps = - StakeDatum - { stakedAmount = defStakedGTs - , owner = PubKeyCredential defOwner - , delegatedTo = Nothing - , lockedBy = mkInputStakeLocks ps - } - --- | Create stake output datum given the parameters. -mkStakeOutputDatum :: Parameters -> StakeDatum -mkStakeOutputDatum ps = - let template = mkStakeInputDatum ps - stakedAmount' = - if ps.alterOutputStake - then alteredStakedGTs - else defStakedGTs - in template - { stakedAmount = stakedAmount' - , lockedBy = mkOutputStakeLocks ps - } - --- | Generate some input proposals and their corresponding output proposals. -mkProposals :: Parameters -> [(ProposalDatum, ProposalDatum)] -mkProposals ps = forEachProposalId ps $ mkProposalDatumPair ps - --- | Create the input proposal datum. -mkProposalInputDatum :: Parameters -> ProposalId -> ProposalDatum -mkProposalInputDatum p pid = fst $ mkProposalDatumPair p pid - --- | Create a input proposal and its corresponding output proposal. -mkProposalDatumPair :: - Parameters -> - ProposalId -> - (ProposalDatum, ProposalDatum) -mkProposalDatumPair params pid = - let inputVotes = mkInputVotes params.stakeRole $ fromDiscrete defStakedGTs - - input = - ProposalDatum - { proposalId = pid - , effects = emptyEffectFor votesTemplate - , status = params.proposalStatus - , cosigners = [PubKeyCredential defOwner] - , thresholds = def - , votes = inputVotes - , timingConfig = def - , startingTime = ProposalStartingTime 0 - } - - output = - if params.retractVotes - then input {votes = votesTemplate} - else input - in (input, output) - where - -- Assemble the votes of the input proposal based on 'votesTemplate'. - mkInputVotes :: - StakeRole -> - -- The staked amount/votes. - Integer -> - ProposalVotes - mkInputVotes Creator _ = - ProposalVotes $ - StrictMap.adjust (const 1000) defVoteFor $ - votesTemplate.getProposalVotes - mkInputVotes Irrelevant _ = votesTemplate - mkInputVotes _ vc = - ProposalVotes $ - StrictMap.adjust (const vc) defVoteFor $ - votesTemplate.getProposalVotes - --- | Create a 'TxInfo' that tries to unlock a stake. -unlockStake :: forall b. CombinableBuilder b => Parameters -> b -unlockStake ps = - let pst = Value.singleton proposalPolicySymbol "" 1 - sst = Value.assetClassValue stakeAssetClass 1 - - pIODatums = mkProposals ps - - proposals = - foldMap - ( \((i, o), idx) -> - mconcat - [ input $ - mconcat - [ script proposalValidatorHash - , withValue pst - , withDatum i - , withRef (mkProposalRef idx) - , withRedeemer proposalRedeemer - ] - , output $ - mconcat - [ script proposalValidatorHash - , withValue (sortValue $ pst <> minAda) - , withDatum o - ] - ] - ) - (zip pIODatums [0 ..]) - - stakeValue = - sortValue $ - mconcat - [ Value.assetClassValue - (untag governor.gtClassRef) - (fromDiscrete defStakedGTs) - , sst - , minAda - ] - - sInDatum = mkStakeInputDatum ps - sOutDatum = mkStakeOutputDatum ps - - stakes = - mconcat - [ input $ - mconcat - [ script stakeValidatorHash - , withValue stakeValue - , withDatum sInDatum - , withRef stakeRef - ] - , output $ - mconcat - [ script stakeValidatorHash - , withValue stakeValue - , withDatum sOutDatum - ] - ] - - builder = - mconcat - [ txId "388bc0b897b3dadcd479da4c88291de4113a50b72ddbed001faf7fc03f11bc52" - , proposals - , stakes - , signedWith defOwner - ] - in builder - --- | Reference to the stake UTXO. -stakeRef :: TxOutRef -stakeRef = TxOutRef stakeTxRef 1 - --- | Generate the reference to a proposal UTXOs, given the index of the proposal. -mkProposalRef :: Int -> TxOutRef -mkProposalRef offset = TxOutRef stakeTxRef $ 2 + fromIntegral offset - --- | Proposal redeemer used by 'mkTestTree', in this case it's always 'Unlock'. -proposalRedeemer :: ProposalRedeemer -proposalRedeemer = Unlock - --- | Stake redeemer used by 'mkTestTree', in this case it's always 'RetractVotes'. -stakeRedeemer :: StakeRedeemer -stakeRedeemer = RetractVotes - --------------------------------------------------------------------------------- - -{- | Legal parameters that retract votes while the proposals is in 'VotingReady' - state, and also remove voter locks from the stake, which is - used to vote on the proposals. --} -mkVoterRetractVotesWhileVotingParameters :: Integer -> Parameters -mkVoterRetractVotesWhileVotingParameters nProposals = - Parameters - { proposalCount = nProposals - , stakeRole = Voter - , retractVotes = True - , removeVoterLock = True - , removeCreatorLock = False - , proposalStatus = VotingReady - , alterOutputStake = False - } - -{- | Legal parameters that retract votes while the proposals is in 'VotingReady' - state, and also remove voter locks from the stake, which is - used to both create and vote on the proposals. --} -mkVoterCreatorRetractVotesWhileVotingParameters :: Integer -> Parameters -mkVoterCreatorRetractVotesWhileVotingParameters nProposals = - Parameters - { proposalCount = nProposals - , stakeRole = Both - , retractVotes = True - , removeVoterLock = True - , removeCreatorLock = False - , proposalStatus = VotingReady - , alterOutputStake = False - } - -{- | Legal parameters that remove creator locks from the stake while the - proposals is in 'Finished' state. The stake was only used for creating - the proposals. --} -mkCreatorRemoveCreatorLocksWhenFinishedParameters :: Integer -> Parameters -mkCreatorRemoveCreatorLocksWhenFinishedParameters nProposals = - Parameters - { proposalCount = nProposals - , stakeRole = Creator - , retractVotes = False - , removeVoterLock = False - , removeCreatorLock = True - , proposalStatus = Finished - , alterOutputStake = False - } - -{- | Legal parameters that remove voter and creator locks from the stake while - the proposals is in 'Finished' state. The stake was used for creating - and voting on the proposals. --} -mkVoterCreatorRemoveAllLocksWhenFinishedParameters :: Integer -> Parameters -mkVoterCreatorRemoveAllLocksWhenFinishedParameters nProposals = - Parameters - { proposalCount = nProposals - , stakeRole = Both - , retractVotes = False - , removeVoterLock = True - , removeCreatorLock = True - , proposalStatus = Finished - , alterOutputStake = False - } - -{- Legal parameters that remove voter locks from the stake after the voting - phrase. The stake was used only for voting on the proposals. --} -mkVoterUnlockStakeAfterVotingParameters :: Integer -> [Parameters] -mkVoterUnlockStakeAfterVotingParameters nProposals = - map - ( \st -> - Parameters - { proposalCount = nProposals - , stakeRole = Voter - , retractVotes = False - , removeVoterLock = True - , removeCreatorLock = False - , proposalStatus = st - , alterOutputStake = False - } - ) - [Locked, Finished] - -{- Legal parameters that remove voter locks whenproposals are in phrase. - The stake was used for crating and voting on the proposals. --} -mkVoterCreatorRemoveVoteLocksWhenLockedParameters :: Integer -> Parameters -mkVoterCreatorRemoveVoteLocksWhenLockedParameters nProposals = - Parameters - { proposalCount = nProposals - , stakeRole = Both - , retractVotes = False - , removeVoterLock = True - , removeCreatorLock = False - , proposalStatus = Locked - , alterOutputStake = False - } - -{- | Illegal parameters that retract votes when the proposals are not in voting - phrase. --} -mkRetractVotesWhileNotVoting :: Integer -> [Parameters] -mkRetractVotesWhileNotVoting nProposals = do - role <- enumFrom Voter - status <- [Draft, Locked, Finished] - - pure $ - Parameters - { proposalCount = nProposals - , stakeRole = role - , retractVotes = True - , removeVoterLock = True - , removeCreatorLock = False - , proposalStatus = status - , alterOutputStake = False - } - -{- | Illegal parameter that try to unlock a stake that has nothing to do with - the proposals. --} -mkUnockIrrelevantStakeParameters :: Integer -> [Parameters] -mkUnockIrrelevantStakeParameters nProposals = do - status <- [Draft, VotingReady, Locked, Finished] - retractVotes <- [True, False] - - pure $ - Parameters - { proposalCount = nProposals - , stakeRole = Irrelevant - , retractVotes = retractVotes - , removeVoterLock = True - , removeCreatorLock = True - , proposalStatus = status - , alterOutputStake = False - } - -{- | Illegal parameters that remove the creator locks before the proposals are - 'Finished'. --} -mkRemoveCreatorLockBeforeFinishedParameters :: Integer -> [Parameters] -mkRemoveCreatorLockBeforeFinishedParameters nProposals = do - status <- [Draft, VotingReady, Locked] - - pure $ - Parameters - { proposalCount = nProposals - , stakeRole = Creator - , retractVotes = False - , removeVoterLock = False - , removeCreatorLock = True - , proposalStatus = status - , alterOutputStake = False - } - -{- | Illegal parameters that try to retract votes with a stake that was only used - for creating the proposals. --} -mkRetractVotesWithCreatorStakeParamaters :: Integer -> Parameters -mkRetractVotesWithCreatorStakeParamaters nProposals = - Parameters - { proposalCount = nProposals - , stakeRole = Creator - , retractVotes = True - , removeVoterLock = True - , removeCreatorLock = True - , proposalStatus = VotingReady - , alterOutputStake = False - } - -{- | Illegal parameters that try to change the 'StakeDatum.stakedAmount' field of - the output stake datum. --} -mkAlterStakeParameters :: Integer -> [Parameters] -mkAlterStakeParameters nProposals = do - role <- enumFrom Voter - status <- [Draft, Locked, Finished] - - pure $ - Parameters - { proposalCount = nProposals - , stakeRole = role - , retractVotes = True - , removeVoterLock = True - , removeCreatorLock = False - , proposalStatus = status - , alterOutputStake = True - } - --------------------------------------------------------------------------------- - -{- | Create a test tree that runs both the stake validator and the proposal - validator. --} -mkTestTree :: String -> Parameters -> Bool -> SpecificationTree -mkTestTree name ps isValid = group name [stake, proposal] - where - spend = mkSpending unlockStake ps - - stake = - testValidator - (not ps.alterOutputStake) - "stake" - agoraScripts.compiledStakeValidator - (mkStakeInputDatum ps) - stakeRedeemer - (spend stakeRef) - - proposal = - let idx = 0 - pid = ProposalId $ fromIntegral idx - ref = mkProposalRef idx - in testValidator - isValid - "proposal" - agoraScripts.compiledProposalValidator - (mkProposalInputDatum ps pid) - proposalRedeemer - (spend ref) diff --git a/agora-specs/Sample/Proposal/Vote.hs b/agora-specs/Sample/Proposal/Vote.hs index 56a0dd4..7aecebd 100644 --- a/agora-specs/Sample/Proposal/Vote.hs +++ b/agora-specs/Sample/Proposal/Vote.hs @@ -2,13 +2,31 @@ Module : Sample.Proposal.Vote Maintainer : connor@mlabs.city Description: Generate sample data for testing the functionalities of voting on proposals. - Sample and utilities for testing the functionalities of voting on proposals. -} module Sample.Proposal.Vote ( - validVoteParameters, + ParameterBundle (..), + VoteParameters (..), + StakeParameters (..), + StakeInputParameters (..), + StakeOutputParameters (..), + NumProposals (..), + ProposalParameters (..), + TransactionParameters (..), + Validity (..), + vote, mkTestTree, - validVoteAsDelegateParameters, + mkValidOwnerVoteBundle, + mkValidDelegateeVoteBundle, + transparentAssets, + transactionNotAuthorized, + voteForNonexistentOutcome, + noProposal, + moreThanOneProposals, + invalidLocks, + destroyStakes, + insufficientAmount, + insufficientAmount1, ) where import Agora.Governor (Governor (..)) @@ -26,91 +44,116 @@ import Agora.Proposal.Time ( ) import Agora.Scripts (AgoraScripts (..)) import Agora.Stake ( - ProposalLock (..), + ProposalLock (Voted), StakeDatum (..), - StakeRedeemer (PermitVote), + StakeRedeemer (Destroy, PermitVote), ) import Data.Default (Default (def)) import Data.Map.Strict qualified as StrictMap +import Data.Maybe (catMaybes) import Data.Tagged (untag) import Plutarch.Context ( input, + mint, + normalizeValue, output, script, signedWith, timeRange, - txId, - withDatum, + withInlineDatum, withRedeemer, withRef, withValue, ) import PlutusLedgerApi.V1.Value qualified as Value -import PlutusLedgerApi.V2 ( - Credential (PubKeyCredential), - PubKeyHash, - TxOutRef (TxOutRef), - ) -import Sample.Proposal.Shared (proposalTxRef, stakeTxRef) +import PlutusLedgerApi.V2 (Credential (PubKeyCredential), PubKeyHash) +import PlutusLedgerApi.V2.Contexts (TxOutRef (TxOutRef)) +import Sample.Proposal.Shared (proposalTxRef) import Sample.Shared ( agoraScripts, governor, minAda, proposalPolicySymbol, proposalValidatorHash, - signer, stakeAssetClass, stakeValidatorHash, ) -import Test.Specification ( - SpecificationTree, - group, - testValidator, - validatorSucceedsWith, - ) +import Test.Specification (SpecificationTree, group, testValidator) import Test.Util ( CombinableBuilder, closedBoundedInterval, mkSpending, pubKeyHashes, - sortValue, ) --- | Reference to the proposal UTXO. -proposalRef :: TxOutRef -proposalRef = TxOutRef proposalTxRef 0 - --- | Reference to the stake UTXO. -stakeRef :: TxOutRef -stakeRef = TxOutRef stakeTxRef 1 - --- | Parameters for creating a voting transaction. -data Parameters = Parameters - { voteFor :: ResultTag - -- ^ The outcome the transaction is voting for. - , voteCount :: Integer - -- ^ The count of votes. - , voteAsDelegate :: Bool - -- ^ Delegate the stake and use it to vote. +data ParameterBundle = ParamerterBundle + { voteParameters :: VoteParameters + , stakeParameters :: StakeParameters + , proposalParameters :: ProposalParameters + , transactionParameters :: TransactionParameters } --- | The public key hash of the stake owner. -stakeOwner :: PubKeyHash -stakeOwner = signer +newtype VoteParameters = VoteParameters {voteFor :: ResultTag} + +data StakeParameters = StakeParameters + { numStakes :: Integer + , stakeInputParameters :: StakeInputParameters + , stakeOutputParameters :: StakeOutputParameters + } + +newtype StakeInputParameters = StakeInputParameters + { perStakeGTs :: Integer + } + +data StakeOutputParameters = StakeOutputParameters + { burnStakes :: Bool + , dontAddNewLock :: Bool + , changeGTAmount :: Bool + , changeAdaAmount :: Bool + } + +data NumProposals = NoProposal | OneProposal | MoreThanOneProposals + +data ProposalParameters = ProposalParameters + { wrongAddedVotes :: Bool + , numProposals :: NumProposals + } + +data SignedBy = Owner | Delegatee | Unknown + +newtype TransactionParameters = TransactionParameters + { signedBy :: SignedBy + } + +data Validity = Validity + { forProposalValidator :: Bool + , forStakeValidator :: Bool + } + +-------------------------------------------------------------------------------- + +stakeOwner :: PubKeyHash +stakeOwner = head pubKeyHashes + +delegatee :: PubKeyHash +delegatee = pubKeyHashes !! 1 + +unknownSig :: PubKeyHash +unknownSig = pubKeyHashes !! 2 + +-------------------------------------------------------------------------------- --- | The votes of the input proposals. initialVotes :: StrictMap.Map ResultTag Integer initialVotes = StrictMap.fromList - [ (ResultTag 0, 42) - , (ResultTag 1, 4242) + [ (ResultTag 0, 114) + , (ResultTag 1, 514) ] --- | The input proposal datum. proposalInputDatum :: ProposalDatum proposalInputDatum = ProposalDatum - { proposalId = ProposalId 42 + { proposalId = ProposalId 22 , effects = StrictMap.fromList [ (ResultTag 0, StrictMap.empty) @@ -124,178 +167,388 @@ proposalInputDatum = , startingTime = ProposalStartingTime 0 } --- | The locks of the input stake. -existingLocks :: [ProposalLock] -existingLocks = - [ Voted (ProposalId 0) (ResultTag 0) - , Voted (ProposalId 1) (ResultTag 2) - ] +mkProposalRedeemer :: VoteParameters -> ProposalRedeemer +mkProposalRedeemer v = Vote v.voteFor -delegate :: PubKeyHash -delegate = head pubKeyHashes +mkProposalRef :: Integer -> TxOutRef +mkProposalRef = TxOutRef proposalTxRef -{- | Set the 'StakeDatum.stakedAmount' according to the number of votes being - casted. --} -mkStakeInputDatum :: Parameters -> StakeDatum +numProposals :: NumProposals -> Integer +numProposals NoProposal = 0 +numProposals OneProposal = 1 +numProposals MoreThanOneProposals = 2 + +-------------------------------------------------------------------------------- + +mkStakeRedeemer :: StakeOutputParameters -> StakeRedeemer +mkStakeRedeemer params = + if params.burnStakes + then Destroy + else PermitVote + +mkStakeInputDatum :: StakeInputParameters -> StakeDatum mkStakeInputDatum params = StakeDatum - { stakedAmount = fromInteger params.voteCount + { stakedAmount = fromInteger params.perStakeGTs , owner = PubKeyCredential stakeOwner - , delegatedTo = - if params.voteAsDelegate - then Just (PubKeyCredential delegate) - else Nothing - , lockedBy = existingLocks + , delegatedTo = Just (PubKeyCredential delegatee) + , lockedBy = + [ Voted (ProposalId 0) (ResultTag 0) + , Voted (ProposalId 1) (ResultTag 2) + ] } --- | Create the proposal redeemer. In this case @'Vote' _@ will always be used. -mkProposalRedeemer :: Parameters -> ProposalRedeemer -mkProposalRedeemer params = Vote params.voteFor +mkStakeRef :: Integer -> Integer -> TxOutRef +mkStakeRef o i = TxOutRef proposalTxRef $ o + i --- | Place new proposal locks on the stake. -mkNewLock :: Parameters -> ProposalLock -mkNewLock params = Voted proposalInputDatum.proposalId params.voteFor +-------------------------------------------------------------------------------- -{- | The stake redeemer that is used in 'mkTestTree'. In this case it'll always be - 'PermitVote'. --} -stakeRedeemer :: StakeRedeemer -stakeRedeemer = PermitVote - --- | Create a valid transaction that votes on a propsal, given the parameters. -vote :: forall b. CombinableBuilder b => Parameters -> b +vote :: forall b. CombinableBuilder b => ParameterBundle -> b vote params = let pst = Value.singleton proposalPolicySymbol "" 1 sst = Value.assetClassValue stakeAssetClass 1 --- - stakeInputDatum = mkStakeInputDatum params + stakeInputDatum = + mkStakeInputDatum + params.stakeParameters.stakeInputParameters - --- + stakeInputValue = + normalizeValue $ + sst + <> Value.assetClassValue + (untag governor.gtClassRef) + params.stakeParameters.stakeInputParameters.perStakeGTs + <> minAda - updatedVotes :: StrictMap.Map ResultTag Integer - updatedVotes = StrictMap.adjust (+ params.voteCount) params.voteFor initialVotes + newLock = + Voted + proposalInputDatum.proposalId + params.voteParameters.voteFor - --- + updatedLocks = + if params.stakeParameters.stakeOutputParameters.dontAddNewLock + then stakeInputDatum.lockedBy + else newLock : stakeInputDatum.lockedBy + + stakeOutputDatum = stakeInputDatum {lockedBy = updatedLocks} + + stakeOutputValue = + let changeAmount cond = if cond then (* 100) else id + gtAmount = + changeAmount + params.stakeParameters.stakeOutputParameters.changeGTAmount + params.stakeParameters.stakeInputParameters.perStakeGTs + adaAmount = + changeAmount + params.stakeParameters.stakeOutputParameters.changeAdaAmount + 10_000_000 + in normalizeValue $ + sst + <> Value.assetClassValue + (untag governor.gtClassRef) + gtAmount + <> minAda + <> Value.singleton "" "" adaAmount + + stakeRedeemer = + mkStakeRedeemer params.stakeParameters.stakeOutputParameters + + stakeBuilder :: b + stakeBuilder = + foldMap + ( \i -> + mconcat + [ input $ + mconcat + [ script stakeValidatorHash + , withValue stakeInputValue + , withInlineDatum stakeInputDatum + , withRedeemer stakeRedeemer + , withRef $ mkStakeRef numProposals' i + ] + , if params.stakeParameters.stakeOutputParameters.burnStakes + then mint $ Value.assetClassValue stakeAssetClass (-1) + else + output $ + mconcat + [ script stakeValidatorHash + , withValue stakeOutputValue + , withInlineDatum stakeOutputDatum + ] + ] + ) + [1 .. params.stakeParameters.numStakes] + + -------------------------------------------------------------------------- + + numProposals' = numProposals params.proposalParameters.numProposals + + updatedVotes = + StrictMap.adjust + ( ( if params.proposalParameters.wrongAddedVotes + then (* 10) + else id + ) + . ( + + params.stakeParameters.stakeInputParameters.perStakeGTs + * params.stakeParameters.numStakes + ) + ) + params.voteParameters.voteFor + initialVotes - proposalOutputDatum :: ProposalDatum proposalOutputDatum = proposalInputDatum { votes = ProposalVotes updatedVotes } - --- + proposalRedeemer = mkProposalRedeemer params.voteParameters - -- Off-chain code should do exactly like this: prepend new lock toStatus the list. - updatedLocks :: [ProposalLock] - updatedLocks = mkNewLock params : existingLocks + proposalValue = + normalizeValue $ + pst + <> minAda - --- + proposalBuidler :: b + proposalBuidler = + foldMap + ( \i -> + mconcat + [ input $ + mconcat + [ script proposalValidatorHash + , withValue proposalValue + , withRedeemer proposalRedeemer + , withInlineDatum proposalInputDatum + , withRef $ mkProposalRef i + ] + , output $ + mconcat + [ script proposalValidatorHash + , withValue proposalValue + , withInlineDatum proposalOutputDatum + ] + ] + ) + [1 .. numProposals'] - stakeOutputDatum :: StakeDatum - stakeOutputDatum = - stakeInputDatum - { lockedBy = updatedLocks - } + -------------------------------------------------------------------------- - --- + sig = case params.transactionParameters.signedBy of + Owner -> stakeOwner + Delegatee -> delegatee + Unknown -> unknownSig + + -------------------------------------------------------------------------- validTimeRange = closedBoundedInterval ((def :: ProposalTimingConfig).draftTime + 1) ((def :: ProposalTimingConfig).votingTime - 1) - --- + -------------------------------------------------------------------------- - stakeValue = - sortValue $ - sst - <> Value.assetClassValue (untag governor.gtClassRef) params.voteCount - <> minAda + miscBuilder :: b + miscBuilder = + mconcat + [ signedWith sig + , timeRange validTimeRange + ] - signer = - if params.voteAsDelegate - then delegate - else stakeOwner + -------------------------------------------------------------------------- + builder :: b builder = mconcat - [ txId "827598fb2d69a896bbd9e645bb14c307df907f422b39eecbe4d6329bc30b428c" - , signedWith signer - , timeRange validTimeRange - , input $ - mconcat - [ script proposalValidatorHash - , withValue pst - , withDatum proposalInputDatum - , withRef proposalRef - , withRedeemer $ mkProposalRedeemer params - ] - , input $ - mconcat - [ script stakeValidatorHash - , withValue stakeValue - , withDatum stakeInputDatum - , withRef stakeRef - ] - , output $ - mconcat - [ script proposalValidatorHash - , withValue pst - , withDatum proposalOutputDatum - ] - , output $ - mconcat - [ script stakeValidatorHash - , withValue stakeValue - , withDatum stakeOutputDatum - ] + [ stakeBuilder + , proposalBuidler + , miscBuilder ] in builder ---- +-------------------------------------------------------------------------------- --- | Valida parameters that vote on the proposal. -validVoteParameters :: Parameters -validVoteParameters = - Parameters - { voteFor = ResultTag 0 - , voteCount = 27 - , voteAsDelegate = False - } - -validVoteAsDelegateParameters :: Parameters -validVoteAsDelegateParameters = - validVoteParameters - { voteAsDelegate = True - } - ---- - -{- | Create a test tree that runs the stake validator and proposal validator to - test the voting functionalities. --} -mkTestTree :: String -> Parameters -> Bool -> SpecificationTree -mkTestTree name ps isValid = group name [proposal, stake] +mkTestTree :: String -> ParameterBundle -> Validity -> SpecificationTree +mkTestTree name ps val = group name $ catMaybes [proposal, stake] where spend = mkSpending vote ps + numProposals' = numProposals ps.proposalParameters.numProposals + proposal = - testValidator - isValid - "proposal" - agoraScripts.compiledProposalValidator - proposalInputDatum - (mkProposalRedeemer ps) - (spend proposalRef) + case ps.proposalParameters.numProposals of + NoProposal -> Nothing + _ -> + Just $ + testValidator + val.forProposalValidator + "proposal" + agoraScripts.compiledProposalValidator + proposalInputDatum + (mkProposalRedeemer ps.voteParameters) + (spend $ mkProposalRef 1) stake = - let stakeInputDatum = mkStakeInputDatum ps - in validatorSucceedsWith - "stake" - agoraScripts.compiledStakeValidator - stakeInputDatum - stakeRedeemer - (spend stakeRef) + case ps.stakeParameters.numStakes of + 0 -> error "At least one stake" + _ -> + let stakeRef = mkStakeRef numProposals' 1 + in Just $ + testValidator + val.forStakeValidator + "stake" + agoraScripts.compiledStakeValidator + (mkStakeInputDatum ps.stakeParameters.stakeInputParameters) + (mkStakeRedeemer ps.stakeParameters.stakeOutputParameters) + (spend stakeRef) + +-------------------------------------------------------------------------------- + +-- TODO(Connor) Use optics + +mkValidOwnerVoteBundle :: Integer -> ParameterBundle +mkValidOwnerVoteBundle stakes = + ParamerterBundle + { voteParameters = + VoteParameters + { voteFor = ResultTag 0 + } + , stakeParameters = + StakeParameters + { numStakes = stakes + , stakeInputParameters = + StakeInputParameters + { perStakeGTs = 114514 + } + , stakeOutputParameters = + StakeOutputParameters + { burnStakes = False + , dontAddNewLock = False + , changeGTAmount = False + , changeAdaAmount = False + } + } + , proposalParameters = + ProposalParameters + { wrongAddedVotes = False + , numProposals = OneProposal + } + , transactionParameters = + TransactionParameters + { signedBy = Owner + } + } + +mkValidDelegateeVoteBundle :: Integer -> ParameterBundle +mkValidDelegateeVoteBundle stakes = + let template = mkValidOwnerVoteBundle stakes + in template + { transactionParameters = + template.transactionParameters + { signedBy = Delegatee + } + } + +ownerVoteWithSignleStake :: ParameterBundle +ownerVoteWithSignleStake = mkValidOwnerVoteBundle 1 + +transparentAssets :: ParameterBundle +transparentAssets = + ownerVoteWithSignleStake + { stakeParameters = + ownerVoteWithSignleStake.stakeParameters + { stakeOutputParameters = + ownerVoteWithSignleStake.stakeParameters.stakeOutputParameters + { changeAdaAmount = True + } + } + } + +transactionNotAuthorized :: ParameterBundle +transactionNotAuthorized = + ownerVoteWithSignleStake + { transactionParameters = + ownerVoteWithSignleStake.transactionParameters + { signedBy = Unknown + } + } + +voteForNonexistentOutcome :: ParameterBundle +voteForNonexistentOutcome = + ownerVoteWithSignleStake + { voteParameters = + ownerVoteWithSignleStake.voteParameters + { voteFor = ResultTag 1919810 + } + } + +noProposal :: ParameterBundle +noProposal = + ownerVoteWithSignleStake + { proposalParameters = + ownerVoteWithSignleStake.proposalParameters + { numProposals = NoProposal + } + } + +moreThanOneProposals :: ParameterBundle +moreThanOneProposals = + ownerVoteWithSignleStake + { proposalParameters = + ownerVoteWithSignleStake.proposalParameters + { numProposals = MoreThanOneProposals + } + } + +ownerVoteWithMultipleStakes :: ParameterBundle +ownerVoteWithMultipleStakes = mkValidOwnerVoteBundle 5 + +invalidLocks :: ParameterBundle +invalidLocks = + ownerVoteWithMultipleStakes + { stakeParameters = + ownerVoteWithMultipleStakes.stakeParameters + { stakeOutputParameters = + ownerVoteWithMultipleStakes.stakeParameters.stakeOutputParameters + { dontAddNewLock = True + } + } + } + +destroyStakes :: ParameterBundle +destroyStakes = + ownerVoteWithMultipleStakes + { stakeParameters = + ownerVoteWithMultipleStakes.stakeParameters + { stakeOutputParameters = + ownerVoteWithMultipleStakes.stakeParameters.stakeOutputParameters + { burnStakes = True + } + } + } + +insufficientAmount :: ParameterBundle +insufficientAmount = + ownerVoteWithSignleStake + { stakeParameters = + ownerVoteWithSignleStake.stakeParameters + { stakeInputParameters = + ownerVoteWithSignleStake.stakeParameters.stakeInputParameters + { perStakeGTs = 1 + } + } + } + +insufficientAmount1 :: ParameterBundle +insufficientAmount1 = + ownerVoteWithMultipleStakes + { stakeParameters = + ownerVoteWithMultipleStakes.stakeParameters + { stakeInputParameters = + ownerVoteWithMultipleStakes.stakeParameters.stakeInputParameters + { perStakeGTs = 1 + } + } + } diff --git a/agora-specs/Sample/Shared.hs b/agora-specs/Sample/Shared.hs index 9a572f3..75113e3 100644 --- a/agora-specs/Sample/Shared.hs +++ b/agora-specs/Sample/Shared.hs @@ -189,6 +189,7 @@ instance Default ProposalThresholds where ProposalThresholds { execute = Tagged 1000 , create = Tagged 1 + , toVoting = Tagged 100 , vote = Tagged 100 } diff --git a/agora-specs/Sample/Stake.hs b/agora-specs/Sample/Stake.hs index 7a21ffd..4ee3437 100644 --- a/agora-specs/Sample/Stake.hs +++ b/agora-specs/Sample/Stake.hs @@ -138,7 +138,6 @@ stakeDepositWithdraw config = mconcat [ txId "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be" , signedWith signer - , mint st , input $ mconcat [ script stakeValidatorHash @@ -147,7 +146,7 @@ stakeDepositWithdraw config = st <> Value.assetClassValue (untag governor.gtClassRef) (fromDiscrete stakeBefore.stakedAmount) ) - , withDatum stakeAfter + , withDatum stakeBefore , withRef stakeRef ] , output $ diff --git a/agora-specs/Spec/Proposal.hs b/agora-specs/Spec/Proposal.hs index 6ff1105..fb04441 100644 --- a/agora-specs/Spec/Proposal.hs +++ b/agora-specs/Spec/Proposal.hs @@ -10,8 +10,9 @@ module Spec.Proposal (specs) where import Sample.Proposal.Advance qualified as Advance import Sample.Proposal.Cosign qualified as Cosign import Sample.Proposal.Create qualified as Create -import Sample.Proposal.UnlockStake qualified as UnlockStake +import Sample.Proposal.Unlock qualified as Unlock import Sample.Proposal.Vote qualified as Vote + import Test.Specification ( SpecificationTree, group, @@ -52,8 +53,8 @@ specs = "invalid stake locks" Create.addInvalidLocksParameters True - False True + False , Create.mkTestTree "has reached maximum proposals limit" Create.exceedMaximumProposalsParameters @@ -128,10 +129,62 @@ specs = "voting" [ group "legal" - [ Vote.mkTestTree "ordinary" Vote.validVoteParameters True - , Vote.mkTestTree "delegate" Vote.validVoteAsDelegateParameters True + [ group "different number of stakes" $ + map + ( \s -> + group + (unwords [show s, "stakes"]) + [ Vote.mkTestTree + "by owner" + (Vote.mkValidOwnerVoteBundle s) + (Vote.Validity True True) + , Vote.mkTestTree + "by delegatee" + (Vote.mkValidDelegateeVoteBundle s) + (Vote.Validity True True) + ] + ) + [1, 3, 5, 7, 9] + , Vote.mkTestTree + "transparent non-GT tokens" + Vote.transparentAssets + (Vote.Validity True True) + ] + , group + "illegal" + [ Vote.mkTestTree + "vote for nonexistent outcome" + Vote.voteForNonexistentOutcome + (Vote.Validity False True) + , Vote.mkTestTree + "unauthorized tx" + Vote.transactionNotAuthorized + (Vote.Validity True False) + , Vote.mkTestTree + "no proposal" + Vote.noProposal + (Vote.Validity False False) + , Vote.mkTestTree + "more than one proposals" + Vote.voteForNonexistentOutcome + (Vote.Validity False True) + , Vote.mkTestTree + "locks not added" + Vote.invalidLocks + (Vote.Validity True False) + , Vote.mkTestTree + "attempt to burn stakes" + Vote.destroyStakes + (Vote.Validity True False) + , Vote.mkTestTree + "insufficient staked amount" + Vote.insufficientAmount + (Vote.Validity False True) + , Vote.mkTestTree + "insufficient staked amount" + Vote.insufficientAmount1 + (Vote.Validity False True) ] - -- TODO: add negative test cases ] , group "advancing" @@ -278,103 +331,72 @@ specs = ] ] , group "unlocking" $ - let proposalCountCases = [1, 5, 10, 42] + let stakeCountCases = [1, 3, 5, 7, 9, 11] - mkSubgroupName nProposals = unwords ["with", show nProposals, "proposals"] + mkSubgroupName nStakes = unwords ["with", show nStakes, "stakes"] - mkLegalGroup nProposals = + mkLegalGroup nStakes = group - (mkSubgroupName nProposals) - [ UnlockStake.mkTestTree + (mkSubgroupName nStakes) + [ Unlock.mkTestTree "voter: retract votes while voting" - (UnlockStake.mkVoterRetractVotesWhileVotingParameters nProposals) - True - , UnlockStake.mkTestTree + (Unlock.mkValidVoterRetractVotes nStakes) + (Unlock.Validity True True) + , Unlock.mkTestTree + "voter: retract votes while voting by delegatee" + (Unlock.mkValidDelegateeRetractVotes nStakes) + (Unlock.Validity True True) + , Unlock.mkTestTree "voter/creator: retract votes while voting" - (UnlockStake.mkVoterCreatorRetractVotesWhileVotingParameters nProposals) - True - , UnlockStake.mkTestTree - "creator: remove creator locks when finished" - (UnlockStake.mkCreatorRemoveCreatorLocksWhenFinishedParameters nProposals) - True - , UnlockStake.mkTestTree - "voter/creator: remove all locks when finished" - (UnlockStake.mkVoterCreatorRemoveAllLocksWhenFinishedParameters nProposals) - True - , group "voter: unlock after voting" $ - map - ( \ps -> - let name = show ps.proposalStatus - in UnlockStake.mkTestTree name ps True - ) - (UnlockStake.mkVoterUnlockStakeAfterVotingParameters nProposals) - , UnlockStake.mkTestTree - "voter/creator: remove vote locks when locked" - (UnlockStake.mkVoterCreatorRemoveVoteLocksWhenLockedParameters nProposals) - True + (Unlock.mkValidVoterCreatorRetractVotes nStakes) + (Unlock.Validity True True) + , Unlock.mkTestTree + "creator: remove creator lock after voting" + (Unlock.mkValidCreatorRemoveLock nStakes) + (Unlock.Validity True True) + , Unlock.mkTestTree + "Voter: remove lock after voting" + (Unlock.mkValidVoterRemoveLockAfterVoting nStakes) + (Unlock.Validity True True) ] - mkIllegalGroup nProposals = + mkIllegalGroup nStakes = group - (mkSubgroupName nProposals) + (mkSubgroupName nStakes) [ group "retract votes while not voting" $ map - ( \ps -> - let name = - unwords - [ "role:" - , show ps.stakeRole - , "," - , "status:" - , show ps.proposalStatus - ] - in UnlockStake.mkTestTree name ps False + ( \c -> + Unlock.mkTestTree + "(negative test)" + c + (Unlock.Validity False True) ) - (UnlockStake.mkRetractVotesWhileNotVoting nProposals) - , group "unlock an irrelevant stake" $ - map - ( \ps -> - let name = - unwords - [ "status:" - , show ps.proposalStatus - , "retract votes:" - , show ps.retractVotes - ] - in UnlockStake.mkTestTree name ps False - ) - (UnlockStake.mkUnockIrrelevantStakeParameters nProposals) + (Unlock.mkRetractVotesWhileNotVoting nStakes) , group "remove creator too early" $ map - ( \ps -> - let name = - unwords - ["status:", show ps.proposalStatus] - in UnlockStake.mkTestTree name ps False + ( \c -> + Unlock.mkTestTree + "(negative test)" + c + (Unlock.Validity True False) ) - (UnlockStake.mkRemoveCreatorLockBeforeFinishedParameters nProposals) - , UnlockStake.mkTestTree + (Unlock.mkRemoveCreatorLockBeforeFinished nStakes) + , Unlock.mkTestTree + "unlock an irrelevant stake" + (Unlock.mkUnockIrrelevantStakes nStakes) + (Unlock.Validity False True) + , Unlock.mkTestTree "creator: retract votes" - (UnlockStake.mkRetractVotesWithCreatorStakeParamaters nProposals) - False - , group "alter output stake datum" $ - map - ( \ps -> - let name = - unwords - [ "role:" - , show ps.stakeRole - , "," - , "status:" - , show ps.proposalStatus - ] - in UnlockStake.mkTestTree name ps False - ) - (UnlockStake.mkAlterStakeParameters nProposals) + (Unlock.mkCreatorRetractVotes nStakes) + (Unlock.Validity False True) + , Unlock.mkTestTree + "change output stake value" + (Unlock.mkChangeOutputStakeValue nStakes) + (Unlock.Validity True False) ] - legalGroup = group "legal" $ map mkLegalGroup proposalCountCases - illegalGroup = group "illegal" $ map mkIllegalGroup proposalCountCases + legalGroup = group "legal" $ map mkLegalGroup stakeCountCases + illegalGroup = group "illegal" $ map mkIllegalGroup stakeCountCases in [legalGroup, illegalGroup] ] ] diff --git a/agora.cabal b/agora.cabal index ef56307..717cf1c 100644 --- a/agora.cabal +++ b/agora.cabal @@ -198,7 +198,7 @@ library agora-specs Sample.Proposal.Cosign Sample.Proposal.Create Sample.Proposal.Shared - Sample.Proposal.UnlockStake + Sample.Proposal.Unlock Sample.Proposal.Vote Sample.Shared Sample.Stake diff --git a/agora/Agora/Governor/Scripts.hs b/agora/Agora/Governor/Scripts.hs index a11af86..f5833d7 100644 --- a/agora/Agora/Governor/Scripts.hs +++ b/agora/Agora/Governor/Scripts.hs @@ -45,7 +45,6 @@ import Agora.Scripts ( stakeSTSymbol, ) import Agora.Stake ( - PProposalLock (..), PStakeDatum (..), pnumCreatedProposals, ) @@ -469,31 +468,6 @@ governorValidator as = #&& proposalOutputDatumF.timingConfig #== governorInputDatumF.proposalTimings ] - -- Check the output stake has been properly updated. - - let stakeOutputDatum = - passertPJust # "Output stake should be presented" - #$ pfindJust - # getStakeDatum - # pfromData txInfoF.outputs - - stakeOutputLocks = - pfromData $ pfield @"lockedBy" # stakeOutputDatum - - -- The stake should be locked by the newly created proposal. - newLock = - mkRecordConstr - PCreated - ( #created .= governorInputDatumF.nextProposalId - ) - - -- Append new locks to existing locks - expectedProposalLocks = - pcons # pdata newLock # stakeInputDatumF.lockedBy - - pguardC "Stake output locks correct" $ - plistEquals # stakeOutputLocks # expectedProposalLocks - pure $ popaque $ pconstant () ------------------------------------------------------------------------ diff --git a/agora/Agora/Plutarch/Orphans.hs b/agora/Agora/Plutarch/Orphans.hs index bf706d7..882595d 100644 --- a/agora/Agora/Plutarch/Orphans.hs +++ b/agora/Agora/Plutarch/Orphans.hs @@ -8,6 +8,8 @@ import Data.Bifunctor (Bifunctor (bimap)) import Data.Map.Strict qualified as StrictMap import Data.Traversable (for) import Plutarch.Api.V1 (KeyGuarantees (Sorted), PMap) +import Plutarch.Num (PNum) +import Plutarch.SafeMoney (PDiscrete) import PlutusTx qualified import PlutusTx.AssocMap qualified as AssocMap @@ -74,3 +76,6 @@ instance isSorted [] = True isSorted [_] = True isSorted (x : y : xs) = x < y && isSorted (y : xs) + +-- | @since 1.0.0 +deriving anyclass instance PNum (PDiscrete tag) diff --git a/agora/Agora/Proposal.hs b/agora/Agora/Proposal.hs index 526cd62..663f3d1 100644 --- a/agora/Agora/Proposal.hs +++ b/agora/Agora/Proposal.hs @@ -67,8 +67,7 @@ import Plutarch.DataRepr ( ), PDataFields, ) -import Plutarch.Extra.Comonad (pextract) -import Plutarch.Extra.Field (pletAllC) +import Plutarch.Extra.Field (pletAll) import Plutarch.Extra.Function (pbuiltinUncurry) import Plutarch.Extra.IsData ( DerivePConstantViaDataList (DerivePConstantViaDataList), @@ -81,14 +80,14 @@ import Plutarch.Extra.IsData ( import "liqwid-plutarch-extra" Plutarch.Extra.List (pfindJust) import Plutarch.Extra.Map qualified as PM import Plutarch.Extra.Maybe (pfromJust) -import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pguardC, pletC, pmatchC) +import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pguardC, pletC) import Plutarch.Lift ( DerivePConstantViaNewtype (DerivePConstantViaNewtype), PConstantDecl, PUnsafeLiftDecl (type PLifted), ) import Plutarch.Orphans () -import Plutarch.SafeMoney (PDiscrete (PDiscrete)) +import Plutarch.SafeMoney (PDiscrete) import PlutusLedgerApi.V2 (Credential, DatumHash, ScriptHash, ValidatorHash) import PlutusTx qualified @@ -222,7 +221,7 @@ data ProposalStatus This data is stored centrally (in the 'Agora.Governor.Governor') and copied over to 'Proposal's when they are created. - @since 0.1.0 + @since 1.0.0 -} data ProposalThresholds = ProposalThresholds { execute :: Tagged GTTag Integer @@ -232,9 +231,10 @@ data ProposalThresholds = ProposalThresholds -- -- It is recommended this be a high enough amount, in order to prevent DOS from bad -- actors. + , toVoting :: Tagged GTTag Integer + -- ^ How much GT required to to move into 'Locked'. , vote :: Tagged GTTag Integer - -- ^ How much GT required to allow voting to happen. - -- (i.e. to move into 'VotingReady') + -- ^ How much GT required to vote on a outcome. } deriving stock ( -- | @since 0.1.0 @@ -553,7 +553,7 @@ deriving via (DerivePConstantViaEnum ProposalStatus PProposalStatus) instance (P {- | Plutarch-level version of 'ProposalThresholds'. - @since 0.1.0 + @since 1.0.0 -} newtype PProposalThresholds (s :: S) = PProposalThresholds { getProposalThresholds :: @@ -562,6 +562,7 @@ newtype PProposalThresholds (s :: S) = PProposalThresholds ( PDataRecord '[ "execute" ':= PDiscrete GTTag , "create" ':= PDiscrete GTTag + , "toVoting" ':= PDiscrete GTTag , "vote" ':= PDiscrete GTTag ] ) @@ -617,6 +618,8 @@ newtype PProposalVotes (s :: S) PlutusType , -- | @since 0.1.0 PIsData + , -- | @since 1.0.0 + PShow ) -- | @since 0.2.0 @@ -949,23 +952,18 @@ pneutralOption = phoistAcyclic $ -} pisProposalThresholdsValid :: forall (s :: S). Term s (PProposalThresholds :--> PBool) pisProposalThresholdsValid = phoistAcyclic $ - plam $ \thresholds -> unTermCont $ do - thresholdsF <- pletAllC thresholds - - PDiscrete execute' <- pmatchC thresholdsF.execute - PDiscrete draft' <- pmatchC thresholdsF.create - PDiscrete vote' <- pmatchC thresholdsF.vote - - execute <- pletC $ pextract # execute' - draft <- pletC $ pextract # draft' - vote <- pletC $ pextract # vote' - - pure $ + plam $ + flip pletAll $ \thresholdsF -> foldr1 (#&&) - [ ptraceIfFalse "Execute threshold is less than or equal to 0" $ 0 #<= execute - , ptraceIfFalse "Draft threshold is less than or equal to 0" $ 0 #<= draft - , ptraceIfFalse "Vote threshold is less than or equal to 0" $ 0 #<= vote + [ ptraceIfFalse "Execute threshold is less than or equal to 0" $ + 0 #<= pfromData thresholdsF.execute + , ptraceIfFalse "Create threshold is less than or equal to 0" $ + 0 #<= pfromData thresholdsF.create + , ptraceIfFalse "toVoting threshold is less than or equal to 0" $ + 0 #<= pfromData thresholdsF.toVoting + , ptraceIfFalse "Vote threshold is less than or equal to 0" $ + 0 #<= pfromData thresholdsF.vote ] {- | Retract votes given the option and the amount of votes. diff --git a/agora/Agora/Proposal/Scripts.hs b/agora/Agora/Proposal/Scripts.hs index 2562d39..9d7f5ec 100644 --- a/agora/Agora/Proposal/Scripts.hs +++ b/agora/Agora/Proposal/Scripts.hs @@ -29,17 +29,16 @@ import Agora.Proposal.Time ( ) import Agora.Scripts (AgoraScripts, governorSTSymbol, proposalSTSymbol, stakeSTAssetClass) import Agora.Stake ( - PProposalLock (PVoted), PStakeDatum, pextractVoteOption, pgetStakeRole, - pisCreator, pisIrrelevant, pisPureCreator, pisVoter, ) import Agora.Utils ( plistEqualsBy, + pmapMaybe, ) import Plutarch.Api.V1 (PCredential) import Plutarch.Api.V1.AssocMap (plookup) @@ -53,7 +52,7 @@ import Plutarch.Api.V2 ( PValidator, ) import Plutarch.Extra.AssetClass (passetClass, passetClassValueOf) -import Plutarch.Extra.Category (PCategory (pidentity), PSemigroupoid ((#>>>))) +import Plutarch.Extra.Category (PCategory (pidentity)) import Plutarch.Extra.Comonad (pextract) import Plutarch.Extra.Field (pletAll, pletAllC) import "liqwid-plutarch-extra" Plutarch.Extra.List (pfindJust) @@ -73,6 +72,7 @@ import Plutarch.Extra.ScriptContext ( pisTokenSpent, ptryFromOutputDatum, ) +import Plutarch.Extra.Sum (PSum (PSum)) import "liqwid-plutarch-extra" Plutarch.Extra.TermCont ( pguardC, pletC, @@ -80,6 +80,7 @@ import "liqwid-plutarch-extra" Plutarch.Extra.TermCont ( pmatchC, ptryFromC, ) +import Plutarch.Extra.Traversable (pfoldMap) import Plutarch.Extra.Value (psymbolValueOf) import Plutarch.SafeMoney (PDiscrete (PDiscrete)) import Plutarch.Unsafe (punsafeCoerce) @@ -154,13 +155,9 @@ data PWitnessMultipleStakeContext (s :: S) = PWitnessMultipleStakeContext instance DerivePlutusType PWitnessMultipleStakeContext where type DPTStrat _ = PlutusTypeScott -{- | Validation context for redeemers which need to modify a single stake. - - @since 1.0.0 --} -data PSpendSingleStakeContext (s :: S) = PSpendSingleStakeContext - { inputStake :: Term s PStakeDatum - , outputStake :: Term s PStakeDatum +-- | @since 1.0.0 +newtype PStakeInputsContext (s :: S) = PStakeInputsContext + { inputStakes :: Term s (PList PStakeDatum) } deriving stock ( -- | @since 1.0.0 @@ -172,8 +169,8 @@ data PSpendSingleStakeContext (s :: S) = PSpendSingleStakeContext ) -- | @since 1.0.0 -instance DerivePlutusType PSpendSingleStakeContext where - type DPTStrat _ = PlutusTypeScott +instance DerivePlutusType PStakeInputsContext where + type DPTStrat _ = PlutusTypeNewtype {- | The validator for Proposals. @@ -186,6 +183,7 @@ instance DerivePlutusType PSpendSingleStakeContext where When voting and unlocking, the proposal must witness a state transition occuring in the relevant Stake. This transition must place a lock on the stake that is tagged with the right 'Agora.Proposal.ResultTag', and 'Agora.Proposal.ProposalId'. + Note that only one proposal per transaction is supported. === Periods @@ -256,66 +254,59 @@ proposalValidator as maximumCosigners = -- * has an PST -- * has the same proposal id as the proposal input -- - -- We match the proposal id here so that we can support multiple - -- proposal inputs in one thansaction. + -- We can handle only one proposal under current design. proposalOutputDatum <- pletC $ - passertPJust - # "Own output should be present" - #$ pfindJust - # plam - ( flip pletAll $ \outputF -> - let pstSymbol = pconstant $ proposalSTSymbol as + passertPJust # "proposal input should present" + #$ pfindJust + # plam + ( flip pletAll $ \outputF -> + let pstSymbol = pconstant $ proposalSTSymbol as - isProposalUTxO = - foldl1 - (#&&) - [ ptraceIfFalse "Own by proposal validator" $ - outputF.address #== proposalInputF.address - , ptraceIfFalse "Has proposal ST" $ - psymbolValueOf # pstSymbol # outputF.value #== 1 - ] + isProposalUTxO = + foldl1 + (#&&) + [ ptraceIfFalse "Own by proposal validator" $ + outputF.address #== proposalInputF.address + , ptraceIfFalse "Has proposal ST" $ + psymbolValueOf # pstSymbol # outputF.value #== 1 + ] - handleProposalUTxO = unTermCont $ do - -- Using inline datum to avoid O(n^2) lookup. - datum <- - pletC $ - pfromData $ - ptrace "Resolve proposal datum" $ - pfromOutputDatum @(PAsData PProposalDatum) - # outputF.datum - # txInfoF.datums - - pure $ - pif - ( pfield @"proposalId" # pto datum - #== proposalInputDatumF.proposalId - ) - (pjust # datum) - pnothing - in pif - isProposalUTxO - handleProposalUTxO - pnothing - ) - # pfromData txInfoF.outputs + handleProposalUTxO = + -- Using inline datum to avoid O(n^2) lookup. + pfromData $ + ptrace "Resolve proposal datum" $ + pfromOutputDatum @(PAsData PProposalDatum) + # outputF.datum + # txInfoF.datums + in pif + isProposalUTxO + (pjust # handleProposalUTxO) + pnothing + ) + # pfromData txInfoF.outputs -------------------------------------------------------------------------- + let AssetClass (sstSymbol, sstName) = stakeSTAssetClass as - -- Handle stake input/output. + sstAssetClass <- + pletC $ + passetClass + # pconstant sstSymbol + # pconstant sstName + + -- Handle stake inputs/outputs. -- Reslove stake datum if the given UTxO is a stake UTxO. getStakeDatum :: Term _ (PTxOut :--> PMaybe PStakeDatum) <- pletC $ plam $ flip (pletFields @'["value", "datum"]) $ \txOutF -> - let AssetClass (stakeSym, _) = stakeSTAssetClass as - - isStakeUTxO = + let isStakeUTxO = -- A stake UTxO is a UTxO that carries SST. - psymbolValueOf - # pconstant stakeSym + passetClassValueOf # txOutF.value + # sstAssetClass #== 1 stake = @@ -328,6 +319,26 @@ proposalValidator as maximumCosigners = # txInfoF.datums in pif isStakeUTxO (pjust # stake) pnothing + spendStakes' :: Term _ ((PStakeInputsContext :--> PUnit) :--> PUnit) <- + pletC $ + plam $ + let stakeInputs = + pmapMaybe + # plam ((getStakeDatum #) . (pfield @"resolved" #)) + # pfromData txInfoF.inputs + + ctx = pcon $ PStakeInputsContext stakeInputs + in (# ctx) + + let spendStakes :: + ( PStakeInputsContext _ -> + TermCont _ () + ) -> + Term _ POpaque + spendStakes c = popaque $ + spendStakes' #$ plam $ \sctx -> + unTermCont $ pmatchC sctx >>= c >> pure (pconstant ()) + -- Witness stakes in reference inputs. witnessStakes' :: Term @@ -388,34 +399,6 @@ proposalValidator as maximumCosigners = witnessStakes' #$ plam $ \sctxF -> unTermCont $ pmatchC sctxF >>= c >> pure (pconstant ()) - -- We don't need to explicitly ensure that there's only one stake in the - -- inputs here - the stake validator will do it for us. - spendSingleStake' :: - Term - s - ((PSpendSingleStakeContext :--> PUnit) :--> PUnit) <- - pletC $ - let stakeInput = - passertPJust # "Stake input should present" #$ pfindJust - # ((pfield @"resolved" @_ @PTxInInfo) #>>> getStakeDatum) - # txInfoF.inputs - - stakeOutput = - passertPJust # "Stake output should present" - #$ pfindJust # getStakeDatum # txInfoF.outputs - - ctx = pcon $ PSpendSingleStakeContext stakeInput stakeOutput - in plam (# ctx) - - let spendSingleStake :: - ( PSpendSingleStakeContext _ -> - TermCont _ () - ) -> - Term _ POpaque - spendSingleStake c = popaque $ - spendSingleStake' #$ plam $ \sctx -> - unTermCont $ pmatchC sctx >>= c >> pure (pconstant ()) - ---------------------------------------------------------------------------- proposalRedeemer <- fst <$> ptryFromC @PProposalRedeemer redeemer @@ -474,8 +457,28 @@ proposalValidator as maximumCosigners = ---------------------------------------------------------------------- - PVote r -> spendSingleStake $ \sctxF -> do - stakeInF <- pletAllC $ pto sctxF.inputStake + PVote r -> spendStakes $ \sctxF -> do + totalStakeAmount <- + pletC $ + pto $ + pfoldMap + # plam + ( \stake -> unTermCont $ do + stakeF <- pletFieldsC @'["stakedAmount", "lockedBy"] stake + + pguardC "Same stake shouldn't vote on the same proposal twice" $ + pnot + #$ pisVoter + #$ pgetStakeRole + # proposalInputDatumF.proposalId + # stakeF.lockedBy + + pure $ pcon $ PSum $ pfromData stakeF.stakedAmount + ) + # sctxF.inputStakes + + pguardC "Exceed minimum amount" $ + thresholdsF.vote #< totalStakeAmount pguardC "Input proposal must be in VotingReady state" $ currentStatus #== pconstant VotingReady @@ -494,10 +497,6 @@ proposalValidator as maximumCosigners = pguardC "Vote option should be valid" $ pisJust #$ plookup # voteFor # voteMap - -- Ensure that no lock with the current proposal id has been put on the stake. - pguardC "Same stake shouldn't vote on the same proposal twice" $ - pnot #$ pisVoter #$ pgetStakeRole # proposalInputDatumF.proposalId # stakeInF.lockedBy - let -- The amount of new votes should be the 'stakedAmount'. -- Update the vote counter of the proposal, and leave other stuff as is. expectedNewVotes = @@ -506,7 +505,7 @@ proposalValidator as maximumCosigners = pupdate # plam ( \votes -> unTermCont $ do - PDiscrete v <- pmatchC stakeInF.stakedAmount + PDiscrete v <- pmatchC totalStakeAmount pure $ pcon $ PJust $ votes + (pextract # v) ) # voteFor @@ -528,76 +527,68 @@ proposalValidator as maximumCosigners = pguardC "Output proposal should be valid" $ proposalOutputDatum #== expectedProposalOut - -- We validate the output stake datum here as well: We need the vote option - -- to create a valid 'ProposalLock', however the vote option is encoded - -- in the proposal redeemer, which is invisible for the stake validator. - - let newProposalLock = - mkRecordConstr - PVoted - ( #votedOn .= proposalInputDatumF.proposalId - .& #votedFor .= pdata voteFor - ) - - -- Prepend the new lock to existing locks - expectedProposalLocks = - pcons - # pdata newProposalLock - # pfromData stakeInF.lockedBy - - pguardC "Output stake should be locked by the proposal" $ - pfield @"lockedBy" # sctxF.outputStake #== expectedProposalLocks + -- Note that the output stake locks validation now happens in the + -- stake validator. ---------------------------------------------------------------------- - PUnlock _ -> spendSingleStake $ \sctxF -> do - stakeInF <- pletAllC $ pto sctxF.inputStake + PUnlock _ -> spendStakes $ \sctxF -> do + let expectedVotes = + pfoldl + # plam + ( \votes stake -> unTermCont $ do + stakeF <- + pletFieldsC + @'["stakedAmount", "lockedBy"] + stake - stakeRole <- pletC $ pgetStakeRole # proposalInputDatumF.proposalId # stakeInF.lockedBy + stakeRole <- + pletC $ + pgetStakeRole + # proposalInputDatumF.proposalId + # stakeF.lockedBy - pguardC "Stake input should be relevant" $ - pnot #$ pisIrrelevant # stakeRole + pguardC "Stake input should be relevant" $ + pnot #$ pisIrrelevant # stakeRole - retractCount <- - pletC $ - pmatch stakeInF.stakedAmount $ \(PDiscrete v) -> pextract # v + let canRetractVotes = + pnot #$ pisPureCreator # stakeRole - -- The votes can only change when the proposal still allows voting. - let shouldUpdateVotes = + voteCount = + pextract + #$ pto + $ pfromData stakeF.stakedAmount + + newVotes = + pretractVotes + # (pextractVoteOption # stakeRole) + # voteCount + # votes + + pure $ pif canRetractVotes newVotes votes + ) + # proposalInputDatumF.votes + # sctxF.inputStakes + + currentTime' = + passertPJust + # "Should be able to get current time" + # currentTime + + inVotingPeriod = + isVotingPeriod # proposalInputDatumF.timingConfig + # proposalInputDatumF.startingTime + # currentTime' + + -- The votes can only change when the proposal still allows voting. + shouldUpdateVotes = currentStatus #== pconstant VotingReady - #&& pnot # (pisPureCreator # stakeRole) - - allowRemovingCreatorLock = - currentStatus #== pconstant Finished - - isCreator = pisCreator # stakeRole - - -- If the stake has been used for creating the proposal, - -- the creator lock can only be removed when the proposal - -- is finished. - -- - -- In other cases, all the locks related to this - -- proposal should be removed. - validateOutputLocks = plam $ \locks -> - plet - ( pgetStakeRole # proposalInputDatumF.proposalId # locks - ) - $ \newStakeRole -> - pif - (isCreator #&& pnot # allowRemovingCreatorLock) - (pisPureCreator # newStakeRole) - (pisIrrelevant # newStakeRole) + #&& inVotingPeriod pguardC "Proposal output correct" $ pif shouldUpdateVotes ( let -- Remove votes and leave other parts of the proposal as it. - expectedVotes = - pretractVotes - # (pextractVoteOption # stakeRole) - # retractCount - # proposalInputDatumF.votes - expectedProposalOut = mkRecordConstr PProposalDatum @@ -618,12 +609,6 @@ proposalValidator as maximumCosigners = proposalOutputDatum #== proposalInputDatum ) - -- At last, we ensure that all locks belong to this proposal will be removed. - stakeOutputLocks <- pletC $ pfield @"lockedBy" # pto sctxF.outputStake - - pguardC "All relevant locks removed from the stake" $ - validateOutputLocks # stakeOutputLocks - ---------------------------------------------------------------------- PAdvanceProposal _ -> unTermCont $ do @@ -674,7 +659,7 @@ proposalValidator as maximumCosigners = pmatchC notTooLate >>= \case PTrue -> do pguardC "More cosigns than minimum amount" $ - punsafeCoerce (pfromData thresholdsF.vote) #< sctxF.totalAmount + punsafeCoerce (pfromData thresholdsF.toVoting) #< sctxF.totalAmount pguardC "All new cosigners are witnessed by their Stake datums" $ plistEqualsBy diff --git a/agora/Agora/Stake.hs b/agora/Agora/Stake.hs index d40c983..b5b3aab 100644 --- a/agora/Agora/Stake.hs +++ b/agora/Agora/Stake.hs @@ -21,8 +21,7 @@ module Agora.Stake ( PStakeRole (..), -- * Validation context - PStakeInputContext (..), - PStakeOutputContext (..), + PSignedBy (..), PSigContext (..), PStakeRedeemerContext (..), PStakeRedeemerHandlerContext (..), @@ -43,14 +42,19 @@ module Agora.Stake ( runStakeRedeemerHandler, ) where -import Agora.Proposal (PProposalId, PProposalRedeemer, PResultTag, ProposalId, ResultTag) +import Agora.Proposal ( + PProposalId, + PProposalRedeemer, + PProposalStatus, + PResultTag, + ProposalId, + ResultTag, + ) import Agora.SafeMoney (GTTag) import Data.Tagged (Tagged) import Generics.SOP qualified as SOP -import Plutarch.Api.V1 (KeyGuarantees (Sorted), PCredential) -import Plutarch.Api.V1.Value (PValue) +import Plutarch.Api.V1 (PCredential) import Plutarch.Api.V2 ( - AmountGuarantees (Positive), PMaybeData, PTxInfo, ) @@ -58,7 +62,6 @@ import Plutarch.DataRepr ( DerivePConstantViaData (DerivePConstantViaData), PDataFields, ) -import Plutarch.Extra.AssetClass (PAssetClass) import Plutarch.Extra.Field (pletAll) import Plutarch.Extra.IsData ( DerivePConstantViaDataList (DerivePConstantViaDataList), @@ -250,6 +253,8 @@ newtype PStakeDatum (s :: S) = PStakeDatum PEq , -- | @since 1.0.0 PDataFields + , -- | @since 1.0.0 + PShow ) instance DerivePlutusType PStakeDatum where @@ -429,61 +434,11 @@ instance DerivePlutusType PStakeRole where -------------------------------------------------------------------------------- -{- | Represent the stake being spent. - - @since 1.0.0 --} -data PStakeInputContext (s :: S) = PStakeInput - { ownInputDatum :: Term s PStakeDatum - -- ^ The stake datum of said stake. - , ownInputValue :: Term s (PValue 'Sorted 'Positive) - -- ^ The value carried by the stake UTxO. - } - deriving stock - ( -- | @since 1.0.0 - Generic - ) - deriving anyclass - ( -- | @since 1.0.0 - PlutusType - ) - --- | @since 1.0.0 -instance DerivePlutusType PStakeInputContext where - type DPTStrat _ = PlutusTypeScott - -{- | Where the stake will go? - - @since 1.0.0 --} -data PStakeOutputContext (s :: S) - = -- | The output stake is owned by the stake validator. - PStakeOutput - { ownOutputDatum :: Term s PStakeDatum - -- ^ The stake datum of the output stake. - , ownOutputValue :: Term s (PValue 'Sorted 'Positive) - -- ^ The value carried by the stake output UTxO. - } - | -- | The stake is burnt in the transaction. - PStakeBurnt - deriving stock - ( -- | @since 1.0.0 - Generic - ) - deriving anyclass - ( -- | @since 1.0.0 - PlutusType - ) - --- | @since 1.0.0 -instance DerivePlutusType PStakeOutputContext where - type DPTStrat _ = PlutusTypeScott - {- | Who authorizes the transaction? @since 1.0.0 -} -data PSigContext (s :: S) +data PSignedBy (s :: S) = -- | The stake owner authorized the transaction. PSignedByOwner | -- | The delegate authorized the transaction. @@ -499,6 +454,28 @@ data PSigContext (s :: S) PlutusType ) +-- | @since 1.0.0 +instance DerivePlutusType PSignedBy where + type DPTStrat _ = PlutusTypeScott + +{- | The signature context. + + @since 1.0.0 +-} +data PSigContext (s :: S) = PSigContext + { owner :: Term s PCredential + , delegatee :: Term s (PMaybeData (PAsData PCredential)) + , signedBy :: Term s PSignedBy + } + deriving stock + ( -- | @since 1.0.0 + Generic + ) + deriving anyclass + ( -- | @since 1.0.0 + PlutusType + ) + -- | @since 1.0.0 instance DerivePlutusType PSigContext where type DPTStrat _ = PlutusTypeScott @@ -532,9 +509,13 @@ instance DerivePlutusType PStakeRedeemerContext where -} data PProposalContext (s :: S) = -- | A proposal is spent. - PWithProposalRedeemer (Term s PProposalRedeemer) + PSpendProposal + (Term s PProposalId) + (Term s PProposalStatus) + (Term s PProposalRedeemer) | -- | A new proposal is created. PNewProposal + (Term s PProposalId) | -- | No proposal is spent or created. PNoProposal deriving stock @@ -555,12 +536,11 @@ instance DerivePlutusType PProposalContext where @1.0.0 -} data PStakeRedeemerHandlerContext (s :: S) = PStakeRedeemerHandlerContext - { stakeInput :: Term s PStakeInputContext - , stakeOutput :: Term s PStakeOutputContext + { stakeInputDatums :: Term s (PList PStakeDatum) + , stakeOutputDatums :: Term s (PList PStakeDatum) , redeemerContext :: Term s PStakeRedeemerContext , sigContext :: Term s PSigContext , proposalContext :: Term s PProposalContext - , gtAssetClass :: Term s PAssetClass , extraTxContext :: Term s PTxInfo } deriving stock @@ -585,13 +565,19 @@ instance DerivePlutusType PStakeRedeemerHandlerContext where -} type PStakeRedeemerHandler = PStakeRedeemerHandlerContext :--> PUnit -{- | Newtype wrapper around @'ClosedTerm' 'PStakeRedeemerHandler'@ to allow type inference to work. +{- | Newtype wrapper around @'ClosedTerm' 'PStakeRedeemerHandler'@ to allow type + inference to work. @since 1.0.0 -} -newtype PStakeRedeemerHandlerTerm = PStakeRedeemerHandlerTerm (ClosedTerm PStakeRedeemerHandler) +newtype PStakeRedeemerHandlerTerm + = PStakeRedeemerHandlerTerm + (ClosedTerm PStakeRedeemerHandler) -runStakeRedeemerHandler :: PStakeRedeemerHandlerTerm -> ClosedTerm PStakeRedeemerHandler +-- | @since 1.0.0 +runStakeRedeemerHandler :: + PStakeRedeemerHandlerTerm -> + ClosedTerm PStakeRedeemerHandler runStakeRedeemerHandler (PStakeRedeemerHandlerTerm t) = t {- | A collection of stake redeemer handlers for each stake redeemers. @@ -666,7 +652,14 @@ pisIrrelevant = phoistAcyclic $ @since 0.2.0 -} -pgetStakeRole :: forall (s :: S). Term s (PProposalId :--> PBuiltinList (PAsData PProposalLock) :--> PStakeRole) +pgetStakeRole :: + forall (s :: S). + Term + s + ( PProposalId + :--> PBuiltinList (PAsData PProposalLock) + :--> PStakeRole + ) pgetStakeRole = phoistAcyclic $ plam $ \pid locks -> pfoldl @@ -688,7 +681,14 @@ pgetStakeRole = phoistAcyclic $ # pcon PIrrelevant # locks where - pcombineStakeRole :: forall (s :: S). Term s (PStakeRole :--> PStakeRole :--> PStakeRole) + pcombineStakeRole :: + forall (s :: S). + Term + s + ( PStakeRole + :--> PStakeRole + :--> PStakeRole + ) pcombineStakeRole = phoistAcyclic $ plam $ \x y -> let cannotCombine = ptraceError "duplicate roles" diff --git a/agora/Agora/Stake/Redeemers.hs b/agora/Agora/Stake/Redeemers.hs index d179876..01216ec 100644 --- a/agora/Agora/Stake/Redeemers.hs +++ b/agora/Agora/Stake/Redeemers.hs @@ -14,138 +14,247 @@ module Agora.Stake.Redeemers ( pdepositWithdraw, ) where -import Agora.Proposal (PProposalRedeemer (PUnlock, PVote)) +import Agora.Proposal ( + PProposalId, + PProposalRedeemer (PUnlock, PVote), + ProposalStatus (Finished), + ) import Agora.Stake ( - PProposalContext (PNewProposal, PWithProposalRedeemer), - PSigContext (PSignedByOwner, PUnknownSig), + PProposalContext ( + PNewProposal, + PNoProposal, + PSpendProposal + ), + PProposalLock (PCreated, PVoted), + PSigContext (owner, signedBy), + PSignedBy ( + PSignedByDelegate, + PSignedByOwner, + PUnknownSig + ), PStakeDatum (PStakeDatum), - PStakeInputContext (PStakeInput), - PStakeOutputContext (PStakeBurnt, PStakeOutput), - PStakeRedeemerContext (PDepositWithdrawDelta, PNoMetadata, PSetDelegateTo), + PStakeRedeemerContext ( + PDepositWithdrawDelta, + PNoMetadata, + PSetDelegateTo + ), PStakeRedeemerHandler, - PStakeRedeemerHandlerContext (..), + PStakeRedeemerHandlerContext ( + proposalContext, + redeemerContext, + sigContext, + stakeInputDatums, + stakeOutputDatums + ), pstakeLocked, ) +import Agora.Utils (pdeleteBy, pfromSingleton, pisSingleton) import Plutarch.Api.V1.Address (PCredential) -import Plutarch.Api.V1.Value (AmountGuarantees (Positive), PValue) import Plutarch.Api.V2 (PMaybeData) -import Plutarch.Extra.Field (pletAllC) +import Plutarch.Extra.Field (pletAll, pletAllC) import Plutarch.Extra.Maybe (pdjust, pdnothing, pmaybeData) import Plutarch.Extra.Record (mkRecordConstr, (.&), (.=)) import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pguardC, pletC, pmatchC) -import Plutarch.Extra.Value (pgeqByClass, pgeqByClass') import Plutarch.Numeric.Additive (AdditiveMonoid (zero), AdditiveSemigroup ((+))) -import Plutarch.SafeMoney (pdiscreteValue) -import PlutusLedgerApi.V1.Value (AssetClass (..)) import Prelude hiding (Num ((+))) --- | Return true if stake input and output carries the same value. -pownOutputValueUnchanged :: +-- | A wrapper which ensures that no proposal is presented in the transaction. +pwithoutProposal :: forall (s :: S). - Term s (PStakeRedeemerHandlerContext :--> PBool) -pownOutputValueUnchanged = phoistAcyclic $ - plam $ - flip pmatch $ \ctxF -> unTermCont $ do - PStakeInput _ inVal <- pmatchC ctxF.stakeInput - PStakeOutput _ outVal <- pmatchC ctxF.stakeOutput + Term + s + (PStakeRedeemerHandler :--> PStakeRedeemerHandler) +pwithoutProposal = phoistAcyclic $ + plam $ \f ctx -> pmatch ctx $ \ctxF -> + pif + ( pmatch ctxF.proposalContext $ \case + PNoProposal -> pconstant True + _ -> pconstant False + ) + (f # ctx) + (ptraceError "No proposal is allowed") - pure $ inVal #== outVal +{- | Validate stake outputs given a function that converts an input stake datum + to an ouput stake datum. / O(n^2) /. +-} +pbatchUpdateInputs :: + forall (s :: S). + Term + s + ( (PStakeDatum :--> PStakeDatum :--> PBool) + :--> PStakeRedeemerHandlerContext + :--> PBool + ) +pbatchUpdateInputs = phoistAcyclic $ + plam $ \f -> flip pmatch $ \ctxF -> + pnull #$ pfoldr + # (pdeleteBy # f) + # ctxF.stakeOutputDatums + # ctxF.stakeInputDatums + +-- | Extract the 'PSigContext.signedBy' field from 'PStakeRedeemerHandlerContext'. +pgetSignedBy :: + forall (s :: S). + Term + s + (PStakeRedeemerHandlerContext :--> PSignedBy) +pgetSignedBy = phoistAcyclic $ + plam $ \ctx -> unTermCont $ do + ctxF <- pmatchC ctx + sctxF <- pmatchC ctxF.sigContext + pure sctxF.signedBy + +-- | Return true if the tx is authorized by either the owner or the delegatee. +pisSignedBy :: + forall (s :: S). + Term + s + (PBool :--> PStakeRedeemerHandlerContext :--> PBool) +pisSignedBy = phoistAcyclic $ + plam $ \byDelegate ctx -> + pmatch (pgetSignedBy # ctx) $ \case + PSignedByOwner -> pconstant True + PSignedByDelegate -> byDelegate + PUnknownSig -> pconstant False -- | Return true if only the @lockedBy@ field of the stake datum is updated. ponlyLocksUpdated :: forall (s :: S). - Term s (PStakeRedeemerHandlerContext :--> PBool) + Term + s + ( ( PBuiltinList (PAsData PProposalLock) + :--> PBuiltinList (PAsData PProposalLock) + ) + :--> PStakeRedeemerHandlerContext + :--> PBool + ) ponlyLocksUpdated = phoistAcyclic $ - plam $ - flip pmatch $ \ctxF -> unTermCont $ do - PStakeInput inDat _ <- pmatchC ctxF.stakeInput - PStakeOutput outDat _ <- pmatchC ctxF.stakeOutput + plam $ \f -> + pbatchUpdateInputs #$ plam $ \i o -> + pletAll i $ \iF -> + let newLocks = f # pfromData iF.lockedBy - inDatF <- pletAllC inDat - - let onlyLocksUpdated = - let templateStakeDatum = - mkRecordConstr - PStakeDatum - ( #stakedAmount .= inDatF.stakedAmount - .& #owner .= inDatF.owner - .& #delegatedTo .= inDatF.delegatedTo - .& #lockedBy .= pfield @"lockedBy" # outDat - ) - in outDat #== templateStakeDatum - - pure onlyLocksUpdated - --- | Return true if the transaction is signed by the owner of the stake. -psignedByOwner :: - forall (s :: S). - Term s (PStakeRedeemerHandlerContext :--> PBool) -psignedByOwner = phoistAcyclic $ - plam $ - flip pmatch $ \ctxF -> pmatch ctxF.sigContext $ \case - PSignedByOwner -> pconstant True - _ -> pconstant False + expected = + mkRecordConstr + PStakeDatum + ( #stakedAmount .= iF.stakedAmount + .& #owner .= iF.owner + .& #delegatedTo .= iF.delegatedTo + .& #lockedBy .= pdata newLocks + ) + in expected #== o -- | Validation logic shared between 'ppermitVote' and 'retractVote'. pvoteHelper :: forall (s :: S). Term s - ( (PProposalContext :--> PBool) + ( ( PStakeRedeemerHandlerContext + :--> PBuiltinList (PAsData PProposalLock) + :--> PBuiltinList (PAsData PProposalLock) + ) :--> PStakeRedeemerHandler ) pvoteHelper = phoistAcyclic $ plam $ \valProposalCtx ctx -> unTermCont $ do - ctxF <- pmatchC ctx - pguardC "Owner or delegate signs this transaction" $ - pmatch ctxF.sigContext $ \case - PUnknownSig -> pconstant False - _ -> pconstant True + pisSignedBy # pconstant True # ctx -- This puts trust into the Proposal. The Proposal must necessarily check -- that this is not abused. - pguardC "Proposal ST spent" $ - valProposalCtx # ctxF.proposalContext - - pguardC "A UTXO must exist with the correct output" $ - let valueCorrect = pownOutputValueUnchanged # ctx - outputDatumCorrect = ponlyLocksUpdated # ctx - in foldl1 - (#&&) - [ ptraceIfFalse "valueCorrect" valueCorrect - , ptraceIfFalse "datumCorrect" outputDatumCorrect - ] + pguardC "Correct outputs" $ + ponlyLocksUpdated # (valProposalCtx # ctx) # ctx pure $ pconstant () +-- | Add new lock the the existing list of locked. +paddNewLock :: + forall (s :: S). + Term + s + ( PProposalLock + :--> PBuiltinList (PAsData PProposalLock) + :--> PBuiltinList (PAsData PProposalLock) + ) +paddNewLock = phoistAcyclic $ + plam $ + -- Prepend the lock. + \newLock -> pcons # pdata newLock + {- | Default implementation of 'Agora.Stake.PermitVote'. @since 1.0.0 -} ppermitVote :: forall (s :: S). Term s PStakeRedeemerHandler -ppermitVote = pvoteHelper #$ phoistAcyclic $ - plam $ - flip pmatch $ \case - PWithProposalRedeemer r -> pmatch r $ \case - PVote _ -> pconstant True - _ -> ptrace "Expected Vote" $ pconstant False - PNewProposal -> pconstant True - _ -> pconstant False +ppermitVote = phoistAcyclic $ + pvoteHelper #$ phoistAcyclic $ + plam $ \ctx -> unTermCont $ do + ctxF <- pmatchC ctx + + let withOnlyOneStakeInput = + plam $ \lock -> unTermCont $ do + pguardC "Only one stake input allowed" $ + pisSingleton # ctxF.stakeInputDatums + + pure lock + + pure $ + paddNewLock #$ pmatch ctxF.proposalContext $ \case + PSpendProposal pid _ r -> pmatch r $ \case + PVote ((pfromData . (pfield @"resultTag" #)) -> voteFor) -> + mkRecordConstr + PVoted + ( #votedOn .= pdata pid + .& #votedFor .= pdata voteFor + ) + _ -> ptraceError "Expected Vote" + PNewProposal pid -> + withOnlyOneStakeInput + #$ mkRecordConstr + PCreated + ( #created .= pdata pid + ) + _ -> ptraceError "Expected proposal" + +{- | Remove stake locks with the proposal id given the list of existing locks. + The first parameter controls whether to revmove creator locks or not. +-} +premoveLocks :: + forall (s :: S). + Term + s + ( PProposalId + :--> PBool + :--> PBuiltinList (PAsData PProposalLock) + :--> PBuiltinList (PAsData PProposalLock) + ) +premoveLocks = phoistAcyclic $ + plam $ \pid rc -> + pfilter + # plam + ( \(pfromData -> l) -> pnot #$ pmatch l $ \case + PCreated ((pfield @"created" #) -> pid') -> rc #&& pid' #== pid + PVoted ((pfield @"votedOn" #) -> pid') -> pid' #== pid + ) {- | Default implementation of 'Agora.Stake.RetractVotes'. @since 1.0.0 -} pretractVote :: forall (s :: S). Term s PStakeRedeemerHandler -pretractVote = pvoteHelper #$ phoistAcyclic $ - plam $ - flip pmatch $ \case - PWithProposalRedeemer r -> pmatch r $ \case - PUnlock _ -> pconstant True - _ -> ptrace "Expected Unlock" $ pconstant False - _ -> pconstant False +pretractVote = phoistAcyclic $ + pvoteHelper #$ phoistAcyclic $ + plam $ + flip pmatch $ \ctxF -> + pmatch ctxF.proposalContext $ \case + PSpendProposal pid s r -> pmatch r $ \case + PUnlock _ -> + let allowRemovingCreatorLock = + s #== pconstant Finished + in premoveLocks # pid # allowRemovingCreatorLock + _ -> ptraceError "Expected unlock" + _ -> ptraceError "Expected spending proposal" -- | Validation logic shared by 'pdelegateTo' and 'pclearDelegate'. pdelegateHelper :: @@ -156,40 +265,35 @@ pdelegateHelper :: :--> PStakeRedeemerHandler ) pdelegateHelper = phoistAcyclic $ - plam $ \f ctx -> unTermCont $ do + plam $ \f -> pwithoutProposal #$ plam $ \ctx -> unTermCont $ do ctxF <- pmatchC ctx + sigCtxF <- pmatchC ctxF.sigContext - pguardC "Owner signs this transaction" $ psignedByOwner # ctx + pguardC "Owner signs this transaction" $ + pisSignedBy # pconstant False # ctx - PStakeInput inpDat _ <- pmatchC ctxF.stakeInput - PStakeOutput outDat _ <- pmatchC ctxF.stakeOutput - - inpDatF <- pletAllC inpDat - - let maybePkh = f # ctxF.redeemerContext + let newDelegate = f # ctxF.redeemerContext pguardC "Cannot delegate to the owner" $ pmaybeData # pcon PTrue - # plam (\pkh -> pnot #$ inpDatF.owner #== pkh) - # maybePkh + # plam (\pkh -> pnot #$ sigCtxF.owner #== pfromData pkh) + # newDelegate - pguardC "A UTXO must exist with the correct output" $ - let correctOutputDatum = - outDat - #== mkRecordConstr + pguardC "Correct outputs" $ + pbatchUpdateInputs + # plam + ( \i o -> pletAll i $ \iF -> + mkRecordConstr PStakeDatum - ( #stakedAmount .= inpDatF.stakedAmount - .& #owner .= inpDatF.owner - .& #delegatedTo .= pdata maybePkh - .& #lockedBy .= inpDatF.lockedBy + ( #stakedAmount .= iF.stakedAmount + .& #owner .= iF.owner + .& #delegatedTo .= pdata newDelegate + .& #lockedBy .= iF.lockedBy ) - valueCorrect = pownOutputValueUnchanged # ctx - in foldl1 - (#&&) - [ ptraceIfFalse "valueCorrect" valueCorrect - , ptraceIfFalse "datumCorrect" correctOutputDatum - ] + #== o + ) + # ctx pure $ pconstant () @@ -221,16 +325,14 @@ pclearDelegate = pdelegateHelper #$ phoistAcyclic $ -} pdestroy :: forall (s :: S). Term s PStakeRedeemerHandler pdestroy = phoistAcyclic $ - plam $ \ctx -> unTermCont $ do + pwithoutProposal #$ plam $ \ctx -> unTermCont $ do ctxF <- pmatchC ctx - PStakeInput inpDat _ <- pmatchC ctxF.stakeInput - PStakeBurnt <- pmatchC ctxF.stakeOutput - pguardC "Owner signs this transaction" $ - psignedByOwner # ctx + pisSignedBy # pconstant False # ctx - pguardC "Stake unlocked" $ pnot #$ pstakeLocked # inpDat + pguardC "Stake unlocked" $ + pnot #$ pany # pstakeLocked # ctxF.stakeInputDatums pure $ pconstant () @@ -240,64 +342,46 @@ pdestroy = phoistAcyclic $ -} pdepositWithdraw :: forall (s :: S). Term s PStakeRedeemerHandler pdepositWithdraw = phoistAcyclic $ - plam $ \ctx -> unTermCont $ do + pwithoutProposal #$ plam $ \ctx -> unTermCont $ do ctxF <- pmatchC ctx - PStakeInput inpDat inpVal <- pmatchC ctxF.stakeInput - PStakeOutput outDat outVal <- pmatchC ctxF.stakeOutput + pguardC "Owner signs this transaction" $ + pisSignedBy # pconstant False # ctx - pguardC "Stake unlocked" $ pnot #$ pstakeLocked # inpDat + ---------------------------------------------------------------------------- - pguardC "Owner signs this transaction" $ psignedByOwner # ctx + stakeInputDatum <- + pletC $ + ptrace "Single stake input" $ + pfromSingleton # ctxF.stakeInputDatums + stakeInputDatumF <- pletAllC stakeInputDatum - pguardC - "A UTXO must exist with the correct output" - $ unTermCont $ do - inpDatF <- pletAllC inpDat - PDepositWithdrawDelta delta <- pmatchC ctxF.redeemerContext + let stakeOutputDatum = + ptrace "Single stake output" $ + pfromSingleton # ctxF.stakeOutputDatums - let oldStakedAmount = pfromData $ inpDatF.stakedAmount + ---------------------------------------------------------------------------- - newStakedAmount <- pletC $ oldStakedAmount + delta + pguardC "Stake unlocked" $ + pnot #$ pstakeLocked # stakeInputDatum - pguardC "New staked amount should be greater than or equal to 0" $ - zero #<= newStakedAmount + ---------------------------------------------------------------------------- - let expectedDatum = - mkRecordConstr - PStakeDatum - ( #stakedAmount .= pdata newStakedAmount - .& #owner .= inpDatF.owner - .& #delegatedTo .= inpDatF.delegatedTo - .& #lockedBy .= inpDatF.lockedBy - ) - datumCorrect = outDat #== expectedDatum + PDepositWithdrawDelta delta <- pmatchC ctxF.redeemerContext - let valueDelta :: Term _ (PValue _ 'Positive) - valueDelta = pdiscreteValue # ctxF.gtAssetClass # delta + newStakedAmount <- pletC $ stakeInputDatumF.stakedAmount + delta - expectedValue = - inpVal <> valueDelta + pguardC "Non-negative staked amount" $ zero #<= newStakedAmount - gtAssetClassF <- pletAllC ctxF.gtAssetClass + let expectedDatum = + mkRecordConstr + PStakeDatum + ( #stakedAmount .= pdata newStakedAmount + .& #owner .= stakeInputDatumF.owner + .& #delegatedTo .= stakeInputDatumF.delegatedTo + .& #lockedBy .= stakeInputDatumF.lockedBy + ) + + pguardC "Valid output datum" $ expectedDatum #== stakeOutputDatum - let valueCorrect = - foldr1 - (#&&) - [ pgeqByClass' (AssetClass ("", "")) - # outVal - # expectedValue - , pgeqByClass - # gtAssetClassF.currencySymbol - # gtAssetClassF.tokenName - # outVal - # expectedValue - ] - -- - pure $ - foldl1 - (#&&) - [ ptraceIfFalse "valueCorrect" valueCorrect - , ptraceIfFalse "datumCorrect" datumCorrect - ] pure $ pconstant () diff --git a/agora/Agora/Stake/Scripts.hs b/agora/Agora/Stake/Scripts.hs index 530063b..ef09ecf 100644 --- a/agora/Agora/Stake/Scripts.hs +++ b/agora/Agora/Stake/Scripts.hs @@ -12,7 +12,7 @@ module Agora.Stake.Scripts ( ) where import Agora.Credential (authorizationContext, pauthorizedBy) -import Agora.Proposal (PProposalRedeemer) +import Agora.Proposal (PProposalDatum, PProposalRedeemer) import Agora.SafeMoney (GTTag) import Agora.Scripts ( AgoraScripts, @@ -23,17 +23,23 @@ import Agora.Stake ( PProposalContext ( PNewProposal, PNoProposal, - PWithProposalRedeemer + PSpendProposal ), - PSigContext ( + PSigContext (PSigContext), + PSignedBy ( PSignedByDelegate, PSignedByOwner, PUnknownSig ), PStakeDatum, - PStakeInputContext (PStakeInput), - PStakeOutputContext (PStakeBurnt, PStakeOutput), - PStakeRedeemer (PClearDelegate, PDelegateTo, PDepositWithdraw, PDestroy, PPermitVote, PRetractVotes), + PStakeRedeemer ( + PClearDelegate, + PDelegateTo, + PDepositWithdraw, + PDestroy, + PPermitVote, + PRetractVotes + ), PStakeRedeemerContext ( PDepositWithdrawDelta, PNoMetadata, @@ -55,18 +61,21 @@ import Agora.Stake.Redeemers ( ppermitVote, pretractVote, ) +import Agora.Utils (pmapMaybe) import Data.Tagged (Tagged (Tagged)) import Plutarch.Api.V1 ( + KeyGuarantees (Sorted), PCredential (PPubKeyCredential, PScriptCredential), PTokenName, ) import Plutarch.Api.V1.AssocMap (plookup) +import Plutarch.Api.V1.Value (PValue) import Plutarch.Api.V2 ( + AmountGuarantees, PMintingPolicy, PScriptPurpose (PMinting, PSpending), - PTxInInfo, PTxInfo, - PTxOutRef, + PTxOut, PValidator, ) import Plutarch.Extra.AssetClass ( @@ -74,13 +83,13 @@ import Plutarch.Extra.AssetClass ( passetClassValueOf, pvalueOf, ) -import Plutarch.Extra.Bind (PBind ((#>>=))) -import Plutarch.Extra.Field (pletAllC) +import Plutarch.Extra.Field (pletAll) +import Plutarch.Extra.Functor (PFunctor (pfmap)) import "liqwid-plutarch-extra" Plutarch.Extra.List (pfindJust) import Plutarch.Extra.Maybe ( passertPJust, + pfromMaybe, pjust, - pmaybe, pmaybeData, pnothing, ) @@ -100,6 +109,7 @@ import Plutarch.Extra.Value ( psymbolValueOf, ) import Plutarch.SafeMoney ( + pvalueDiscrete, pvalueDiscrete', ) import Plutarch.Unsafe (punsafeCoerce) @@ -235,8 +245,14 @@ mkStakeValidator impl as (Tagged (AssetClass (gtSym, gtTn))) = - plam $ \datum redeemer ctx -> unTermCont $ do - gtAssetClass <- pletC $ passetClass # pconstant gtSym # pconstant gtTn + plam $ \_datum redeemer ctx -> unTermCont $ do + let sstValueOf :: + ( forall (ag :: AmountGuarantees) (s :: S). + Term s (PValue 'Sorted ag :--> PInteger) + ) + sstValueOf = + phoistAcyclic $ + psymbolValueOf # pconstant (stakeSTSymbol as) -------------------------------------------------------------------------- @@ -257,118 +273,152 @@ mkStakeValidator -------------------------------------------------------------------------- - -- Assemble the stake input context. - - stakeInputDatum <- pfromData . fst <$> ptryFromC datum - stakeInputDatumF <- pletAllC $ pto stakeInputDatum - PSpending stakeInputRef <- pmatchC $ pfromData ctxF.purpose - -- The UTxO we are validating, which is also the input stake. - stakeInput <- - pletC $ - pfield @"resolved" - #$ passertPJust # "Malformed script context: own input not found" - #$ pfindTxInByTxOutRef - # (pfield @"_0" # stakeInputRef) - # txInfoF.inputs + let validatedInput = + pfield @"resolved" + #$ passertPJust + # "Malformed script context: validated input not found" + #$ pfindTxInByTxOutRef + # (pfield @"_0" # stakeInputRef) + # txInfoF.inputs - stakeInputF <- pletFieldsC @'["address", "value"] stakeInput + stakeValidatorAddress = pfield @"address" # validatedInput - stakeInputContext <- + -------------------------------------------------------------------------- + + -- Returns stake datum if the given UTxO is a stake UTxO. + getStakeDatum :: Term _ (PTxOut :--> PMaybe PStakeDatum) <- pletC $ - pcon $ - PStakeInput - stakeInputDatum - stakeInputF.value + plam $ \txOut -> unTermCont $ do + txOutF <- pletFieldsC @'["value", "datum", "address"] txOut + + let isStakeUTxO = + foldl1 + (#&&) + [ ptraceIfFalse "Carries SST" $ + sstValueOf # txOutF.value #== 1 + , ptraceIfFalse "Owned by stake validator" $ + txOutF.address #== stakeValidatorAddress + ] + + datum = + ptrace "Resolve stake datum" $ + pfromData $ + pfromOutputDatum @(PAsData PStakeDatum) + # txOutF.datum + # txInfoF.datums + + pure $ pif isStakeUTxO (pjust # datum) pnothing + + -------------------------------------------------------------------------- + + -- Find all stake inputs. + + stakeInputDatums <- + pletC $ + pmapMaybe + # plam ((getStakeDatum #) . (pfield @"resolved" #)) + # pfromData txInfoF.inputs -------------------------------------------------------------------------- -- Assemble the signature context. - signedBy <- pletC $ pauthorizedBy # authorizationContext txInfoF + firstStakeInputDatumF <- + pletFieldsC @'["owner", "delegatedTo"] $ + phead # stakeInputDatums - let ownerSignsTransaction = signedBy # stakeInputDatumF.owner + restOfStakeInputDatums <- pletC $ ptail # stakeInputDatums + + pguardC "All input stakes have the same owner or delegate" $ + let allHaveSameOwner = + pall + # plam + ( (#== firstStakeInputDatumF.owner) + . (pfield @"owner" #) + ) + # restOfStakeInputDatums + allHaveSameDelegate = + pall + # plam + ( (#== firstStakeInputDatumF.delegatedTo) + . (pfield @"delegatedTo" #) + ) + # restOfStakeInputDatums + in allHaveSameOwner #|| allHaveSameDelegate + + authorizedBy <- pletC $ pauthorizedBy # authorizationContext txInfoF + + let ownerSignsTransaction = authorizedBy # firstStakeInputDatumF.owner delegateSignsTransaction = pmaybeData # pconstant False - # plam ((signedBy #) . pfromData) - # pfromData stakeInputDatumF.delegatedTo + # plam ((authorizedBy #) . pfromData) + # pfromData firstStakeInputDatumF.delegatedTo + + signedBy = + pif + ownerSignsTransaction + (pcon PSignedByOwner) + $ pif + delegateSignsTransaction + (pcon PSignedByDelegate) + $ pcon PUnknownSig sigContext <- pletC $ - pif ownerSignsTransaction (pcon PSignedByOwner) $ - pif delegateSignsTransaction (pcon PSignedByDelegate) $ - pcon PUnknownSig + pcon $ + PSigContext + firstStakeInputDatumF.owner + firstStakeInputDatumF.delegatedTo + signedBy -------------------------------------------------------------------------- - stCurrencySymbol <- pletC $ pconstant $ stakeSTSymbol as - mintedST <- pletC $ psymbolValueOf # stCurrencySymbol # txInfoF.mint - valueSpent <- pletC $ pvalueSpent # txInfoF.inputs - spentST <- pletC $ psymbolValueOf # stCurrencySymbol #$ valueSpent + -- Find all stake outputs. - -- The stake validator can only handle one stake in one transaction. + let gtAssetClass = passetClass # pconstant gtSym # pconstant gtTn - pguardC "ST at inputs must be 1" $ - spentST #== 1 - - let oneStakeBurnt = - ptraceIfFalse "Exactly one stake st burnt" $ - mintedST #== (-1) - - -------------------------------------------------------------------------- - - -- Assemble the stake output context. - - let -- Look for the output stake. - stakeOutput = - pfindJust - # plam - ( \output -> unTermCont $ do - outputF <- - pletFieldsC @'["address", "value", "datum"] - output - - let isStakeOutput = - -- The stake should be owned by the stake validator. - outputF.address #== stakeInputF.address - #&& - -- The stake UTxO carries the state thread token. - psymbolValueOf - # stCurrencySymbol - # outputF.value #== 1 - - stakeOutputDatum = - pfromOutputDatum - # outputF.datum - # txInfoF.datums - - context = - pcon $ - PStakeOutput - (pfromData stakeOutputDatum) - outputF.value - - pure $ - pif - isStakeOutput - (pjust # context) - pnothing - ) - # pfromData txInfoF.outputs - - stakeOutputContext <- + -- First step of validating stake outputs. We make sure that every stake + -- output UTxO carries correct amount of GTs specified by its datum. + -- + -- Note that non-GT assets are treated transparently. + stakeOutputDatums <- pletC $ - pmatch stakeOutput $ \case - -- Stake output found. - PJust stakeOutput' -> stakeOutput' - -- Stake output not found, meaning the input stake should be burnt. - PNothing -> unTermCont $ do - pguardC "One stake should be burnt" oneStakeBurnt + pmapMaybe + # plam + ( \output -> + let validateGT = plam $ \stakeDatum -> + let expected = pfield @"stakedAmount" # stakeDatum - pure $ pcon PStakeBurnt + actual = + pvalueDiscrete + # gtAssetClass + # (pfield @"value" # output) + in pif + (expected #== actual) + stakeDatum + (ptraceError "Unmatched GT value") + in pfmap + # validateGT + # (getStakeDatum # output) + ) + # pfromData txInfoF.outputs + + -------------------------------------------------------------------------- + + mintedST <- pletC $ sstValueOf # txInfoF.mint + + pguardC "No new SST minted" $ + foldl1 + (#||) + [ ptraceIfTrue "All stakes burnt" $ + mintedST #< 0 #&& pnull # stakeOutputDatums + , ptraceIfTrue "Nothing burnt" $ + mintedST #== 0 + ] -------------------------------------------------------------------------- @@ -382,42 +432,79 @@ mkStakeValidator # pconstant propCs # pconstant propTn + getProposalDatum <- pletC $ + plam $ + flip pletAll $ \txOutF -> + let isProposalUTxO = + passetClassValueOf + # txOutF.value + # proposalSTClass #== 1 + proposalDatum = + pfromData $ + pfromOutputDatum @(PAsData PProposalDatum) + # txOutF.datum + # txInfoF.datums + in pif isProposalUTxO (pjust # proposalDatum) pnothing + let pstMinted = passetClassValueOf # txInfoF.mint # proposalSTClass #== 1 + newProposalContext = + pcon $ + PNewProposal $ + pfield @"proposalId" + #$ passertPJust # "Proposal output should present" + #$ pfindJust # getProposalDatum # pfromData txInfoF.outputs + + spendProposalContext = + let getProposalRedeemer = plam $ \ref -> + flip (ptryFrom @PProposalRedeemer) fst $ + pto $ + passertPJust + # "Malformed script context: propsoal input not found in redeemer map" + #$ plookup + # pcon + ( PSpending $ + pdcons @_0 + # pdata ref + # pdnil + ) + # txInfoF.redeemers + + getContext = plam $ + flip pletAll $ \inInfoF -> + pfmap + # plam + ( \proposalDatum -> + let id = pfield @"proposalId" # proposalDatum + status = pfield @"status" # proposalDatum + redeemer = getProposalRedeemer # inInfoF.outRef + in pcon $ PSpendProposal id status redeemer + ) + #$ getProposalDatum + # pfromData inInfoF.resolved + + contexts = + pmapMaybe @PList # getContext # pfromData txInfoF.inputs + in -- Can only handle one proposal at a time. + precList + ( \_ h t -> + pif + (pnull # t) + (pjust # h) + (ptraceError "Ambiguous proposal") + ) + (const pnothing) + # contexts + + noProposalContext = pcon PNoProposal + proposalContext <- pletC $ - let convertRedeemer = plam $ \(pto -> dt) -> - ptryFrom @PProposalRedeemer dt fst - - findRedeemer = plam $ \ref -> - plookup - # pcon - ( PSpending $ - pdcons @_0 - # pdata ref - # pdnil - ) - # txInfoF.redeemers - - f :: Term _ (PTxInInfo :--> PMaybe PTxOutRef) - f = plam $ \inInfo -> - let value = pfield @"value" #$ pfield @"resolved" # inInfo - ref = pfield @"outRef" # inInfo - in pif - (passetClassValueOf # value # proposalSTClass #== 1) - (pjust # ref) - pnothing - - proposalRef = pfindJust # f # txInfoF.inputs - in pif pstMinted (pcon PNewProposal) $ - pmaybe - # pcon PNoProposal - # plam - ( \((convertRedeemer #) -> proposalRedeemer) -> - pcon $ PWithProposalRedeemer proposalRedeemer - ) - #$ proposalRef #>>= findRedeemer + pif + pstMinted + newProposalContext + (pfromMaybe # noProposalContext # spendProposalContext) -------------------------------------------------------------------------- @@ -427,12 +514,11 @@ mkStakeValidator plam $ \redeemerContext -> pcon $ PStakeRedeemerHandlerContext - stakeInputContext - stakeOutputContext + stakeInputDatums + stakeOutputDatums redeemerContext sigContext proposalContext - gtAssetClass txInfo noMetadataContext <- @@ -445,7 +531,7 @@ mkStakeValidator -- Call the redeemer handler. - stakeRedeemer :: Term _ PStakeRedeemer <- fst <$> ptryFromC redeemer + stakeRedeemer <- fst <$> ptryFromC redeemer pure $ popaque $ @@ -472,6 +558,7 @@ mkStakeValidator Deposit or withdraw some GT to the stake. + - Only one stake per tx is supported. - Tx must be signed by the owner. - The 'stakedAmount' field must be updated. - The stake must not be locked. @@ -483,9 +570,9 @@ mkStakeValidator Allow a 'ProposalLock' to be put on the stake in order to vote on a proposal. - - A proposal token must be spent alongside the stake. + - A proposal token must be spent alongside the staked. - * Its total votes must be correctly updated to include this stake's + * Its total votes must be correctly updated to include all stakes' contribution. - Tx must be signed by the owner. @@ -494,14 +581,14 @@ mkStakeValidator Remove a 'ProposalLock' set when voting on a proposal. - - A proposal token must be spent alongside the stake. + - A proposal token must be spent or minted alongside the stakes. - Tx must be signed by the owner. === 'Destroy' - Destroy the stake in order to reclaim the min ADA. + Destroy stakes in order to reclaim the GTs. - - The stake must not be locked. + - The stakes must not be locked. - Tx must be signed by the owner. @since 0.1.0 diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 31e9c32..61fc2e6 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -22,13 +22,17 @@ module Agora.Utils ( pstringIntercalate, punwords, pcurrentTimeDuration, + pdelete, + pdeleteBy, + pisSingleton, + pfromSingleton, + pmapMaybe, ) where import Plutarch.Api.V1 (PPOSIXTime, PTokenName, PValidatorHash) import Plutarch.Api.V2 (PScriptHash) -import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pmatchC) +import Plutarch.Extra.Category (PCategory (pidentity)) import Plutarch.Extra.Time (PCurrentTime (PCurrentTime)) -import Plutarch.List (puncons) import Plutarch.Unsafe (punsafeCoerce) import PlutusLedgerApi.V2 ( Address (Address), @@ -57,8 +61,8 @@ validatorHashToTokenName (ValidatorHash hash) = TokenName hash @since 1.0.0 -} -pvalidatorHashToTokenName :: forall (s :: S). Term s PValidatorHash -> Term s PTokenName -pvalidatorHashToTokenName = punsafeCoerce +pvalidatorHashToTokenName :: forall (s :: S). Term s (PValidatorHash :--> PTokenName) +pvalidatorHashToTokenName = phoistAcyclic $ plam punsafeCoerce {- | Safely convert a 'PScriptHash' into a 'PTokenName'. This can be useful for tagging tokens for extra safety. @@ -145,21 +149,23 @@ plistEqualsBy :: (b :: PType) (s :: S). (PIsListLike list1 a, PIsListLike list2 b) => - Term s ((a :--> b :--> PBool) :--> list1 a :--> (list2 b :--> PBool)) -plistEqualsBy = phoistAcyclic $ pfix # go - where - go = plam $ \self eq l1 l2 -> unTermCont $ do - l1' <- pmatchC $ puncons # l1 - l2' <- pmatchC $ puncons # l2 - - case (l1', l2') of - (PJust l1'', PJust l2'') -> do - (PPair h1 t1) <- pmatchC l1'' - (PPair h2 t2) <- pmatchC l2'' - - pure $ eq # h1 # h2 #&& self # eq # t1 # t2 - (PNothing, PNothing) -> pure $ pconstant True - _ -> pure $ pconstant False + Term s ((a :--> b :--> PBool) :--> list1 a :--> list2 b :--> PBool) +plistEqualsBy = phoistAcyclic $ + plam $ \eq -> pfix #$ plam $ \self l1 l2 -> + pelimList + ( \x xs -> + pelimList + ( \y ys -> + -- Avoid comparison if two lists have different length. + self # xs # ys #&& eq # x # y + ) + -- l2 is empty, but l1 is not. + (pconstant False) + l2 + ) + -- l1 is empty, so l2 should be empty as well. + (pnull # l2) + l1 -- | @since 1.0.0 pstringIntercalate :: @@ -190,3 +196,91 @@ pcurrentTimeDuration = phoistAcyclic $ plam $ flip pmatch $ \(PCurrentTime lb ub) -> ub - lb + +{- | / O(n) /. Remove the first occurance of a value from the given list. + + @since 1.0.0 +-} +pdelete :: + forall (a :: PType) (list :: PType -> PType) (s :: S). + (PEq a, PIsListLike list a) => + Term s (a :--> list a :--> list a) +pdelete = phoistAcyclic $ pdeleteBy # plam (#==) + +-- | @since 1.0.0 +pdeleteBy :: + forall (a :: PType) (list :: PType -> PType) (s :: S). + (PIsListLike list a) => + Term s ((a :--> a :--> PBool) :--> a :--> list a :--> list a) +pdeleteBy = phoistAcyclic $ + plam $ \f' x -> plet (f' # x) $ \f -> + precList + ( \self h t -> + pif + (f # h) + t + (pcons # h #$ self # t) + ) + (const pnil) + +{- | / O(1) /.Return true if the given list has only one element. + + @since 1.0.0 +-} +pisSingleton :: + forall (a :: PType) (list :: PType -> PType) (s :: S). + (PIsListLike list a) => + Term s (list a :--> PBool) +pisSingleton = + phoistAcyclic $ + precList + (\_ _ t -> pnull # t) + (const $ pconstant False) + +{- Throws an error if the given list contains zero or more than one elements. + Otherwise returns the only element. + + @since 1.0.0 +-} +pfromSingleton :: + forall (a :: PType) (list :: PType -> PType) (s :: S). + (PIsListLike list a) => + Term s (list a :--> a) +pfromSingleton = + phoistAcyclic $ + precList + ( \_ h t -> + pif + (pnull # t) + h + (ptraceError "More than one element") + ) + (const $ ptraceError "Empty list") + +{- | A version of 'pmap' which can throw out elements and change the list type + along the way. + + @since 1.0.0 +-} +pmapMaybe :: + forall + (listO :: PType -> PType) + (b :: PType) + (listI :: PType -> PType) + (a :: PType) + (s :: S). + (PIsListLike listI a, PIsListLike listO b) => + Term s ((a :--> PMaybe b) :--> listI a :--> listO b) +pmapMaybe = phoistAcyclic $ + plam $ \f -> + precList + ( \self h t -> + pmatch + (f # h) + ( \case + PJust x -> pcons # x + PNothing -> pidentity + ) + # (self # t) + ) + (const pnil) diff --git a/bench.csv b/bench.csv index 45e3301..f54ce86 100644 --- a/bench.csv +++ b/bench.csv @@ -2,474 +2,461 @@ name,cpu,mem,size Agora/Effects/Treasury Withdrawal Effect/effect/Simple,399131111,1039286,4380 Agora/Effects/Treasury Withdrawal Effect/effect/Simple with multiple treasuries ,576074207,1463710,4812 Agora/Effects/Treasury Withdrawal Effect/effect/Mixed Assets,570468813,1465515,4750 -Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/governor validator should pass,119904869,336481,11184 -Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass,174447826,463697,4914 +Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/governor validator should pass,121735742,341472,11153 +Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass,177090417,471484,5021 Agora/Stake/policy/stakeCreation,57193696,166603,3225 -Agora/Stake/validator/stakeDepositWithdraw deposit,182637761,498129,6222 -Agora/Stake/validator/stakeDepositWithdraw withdraw,182637761,498129,6210 -Agora/Stake/validator/set delegate/override existing delegate,122675859,339769,6249 -Agora/Stake/validator/set delegate/remove existing delegate,115805652,322809,6179 -Agora/Stake/validator/set delegate/set delegate to something,120246871,332669,6179 -Agora/Proposal/policy (proposal creation)/legal/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/legal/governor,332489142,864164,11637 -Agora/Proposal/policy (proposal creation)/legal/stake,151814104,404130,6889 -Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/stake,151814104,404130,6889 -Agora/Proposal/policy (proposal creation)/illegal/use other's stake/proposal,34052826,101718,2003 -Agora/Proposal/policy (proposal creation)/illegal/use other's stake/governor,332489142,864164,11606 -Agora/Proposal/policy (proposal creation)/illegal/altered stake/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/proposal,34052826,101718,2042 -Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/stake,157247764,418780,6897 -Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/proposal,34052826,101718,2054 -Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/stake,164512540,440346,6919 -Agora/Proposal/policy (proposal creation)/illegal/loose time range/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/illegal/loose time range/stake,151814104,404130,6889 -Agora/Proposal/policy (proposal creation)/illegal/open time range/proposal,34052826,101718,2030 -Agora/Proposal/policy (proposal creation)/illegal/open time range/stake,151814104,404130,6885 -Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/stake,151814104,404130,6889 -Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/stake,151814104,404130,6889 -Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/proposal,34052826,101718,2034 -Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/stake,151814104,404130,6889 -Agora/Proposal/validator/cosignature/legal/with 1 cosigners: proposal,218125823,619582,11680 -Agora/Proposal/validator/cosignature/legal/with 5 cosigners: proposal,531693721,1458378,13045 -Agora/Proposal/validator/cosignature/legal/with 10 cosigners: proposal,1027310682,2746645,14752 -Agora/Proposal/validator/voting/legal/ordinary/proposal,268264923,732006,12038 -Agora/Proposal/validator/voting/legal/ordinary/stake,162702421,436978,6724 -Agora/Proposal/validator/voting/legal/delegate/proposal,273122899,746206,12108 -Agora/Proposal/validator/voting/legal/delegate/stake,174048586,466701,6829 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,244983640,688501,12489 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,221829223,616387,12252 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,235933887,645129,13515 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,402962600,1095634,12648 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3291 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,241172350,676273,12210 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,218017933,604159,11973 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,232122597,632901,13057 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,400708022,1088128,12283 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,2926 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,211698609,591948,12245 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,210024625,582354,12246 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,222912570,614760,12246 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,207887319,579720,11966 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,206213335,570126,11967 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,219101280,602532,11967 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3291 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,2926 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,402962600,1095634,12648 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3291 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,400708022,1088128,12283 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,80911114,217260,2926 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/forget to mint GATs/proposal,232122597,632901,12411 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,232122597,632901,13057 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,2926 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,232122597,632901,13089 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs with bad token name/authority,12079326,37748,2958 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/proposal,232122597,632901,13051 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/authority,80911114,217260,2920 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/proposal,232122597,632901,13057 -Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/authority,80911114,217260,2926 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,319208360,892803,13405 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,299748829,830677,13168 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,310158607,849431,14431 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,444697828,1212866,13259 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3902 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,311585780,868347,12844 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,292126249,806221,12607 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,302536027,824975,13692 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,440688637,1199246,12707 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3350 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,285923329,796250,13161 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,284249345,786656,13162 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,297137290,819062,13162 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,278300749,771794,12600 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,276626765,762200,12601 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,289514710,794606,12601 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3902 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3350 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,444697828,1212866,13259 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3902 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,440688637,1199246,12707 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3350 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/forget to mint GATs/proposal,302536027,824975,13046 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,302536027,824975,13692 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3350 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,302536027,824975,13724 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3382 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/proposal,302536027,824975,13686 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/authority,80911114,217260,3344 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/proposal,302536027,824975,13692 -Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/authority,80911114,217260,3350 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,541882520,1505709,16152 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,533507647,1473547,15915 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,532832767,1462337,17178 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,569903512,1564562,15090 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,5733 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,522826070,1444569,14751 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,514451197,1412407,14514 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,513776317,1401197,15599 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,560630482,1532600,13978 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,4621 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,508597489,1409156,15908 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,506923505,1399562,15909 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,519811450,1431968,15909 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,489541039,1348016,14507 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,487867055,1338422,14508 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,500755000,1370828,14508 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,5733 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,4621 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,569903512,1564562,15090 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15755485,47872,5733 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,560630482,1532600,13978 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,80911114,217260,4621 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/forget to mint GATs/proposal,513776317,1401197,14953 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,513776317,1401197,15599 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,4621 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,513776317,1401197,15631 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs with bad token name/authority,12079326,37748,4653 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/proposal,513776317,1401197,15593 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/authority,80911114,217260,4614 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/proposal,513776317,1401197,15599 -Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/authority,80911114,217260,4621 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,432660726,1221049,13990 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,252179943,700115,12662 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,266284607,728857,13925 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,417835896,1137498,12921 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3564 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,428849436,1208821,13709 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,248368653,687887,12382 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,262473317,716629,13466 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,415581318,1129992,12556 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3199 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,242049329,675676,12655 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,240375345,666082,12656 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,253263290,698488,12656 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,238238039,663448,12375 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,236564055,653854,12376 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,249452000,686260,12376 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3564 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3199 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,417835896,1137498,12921 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3564 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,415581318,1129992,12556 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3199 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/forget to mint GATs/proposal,262473317,716629,12820 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,262473317,716629,13466 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3199 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,262473317,716629,13498 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3231 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/proposal,262473317,716629,13460 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/authority,80911114,217260,3193 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/proposal,262473317,716629,13466 -Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/authority,80911114,217260,3199 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,506885446,1425351,14905 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,330099549,914405,13578 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,340509327,933159,14841 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,459571124,1254730,13532 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,4175 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,499262866,1400895,14345 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,322476969,889949,13017 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,332886747,908703,14102 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,455561933,1241110,12980 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3623 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,316274049,879978,13571 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,314600065,870384,13572 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,327488010,902790,13572 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,308651469,855522,13010 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,306977485,845928,13011 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,319865430,878334,13011 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,4175 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3623 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,459571124,1254730,13532 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15755485,47872,4175 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,455561933,1241110,12980 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3623 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/forget to mint GATs/proposal,332886747,908703,13456 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,332886747,908703,14102 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3623 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,332886747,908703,14134 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3655 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/proposal,332886747,908703,14096 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/authority,80911114,217260,3617 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/proposal,332886747,908703,14102 -Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/authority,80911114,217260,3623 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,729559606,2038257,17651 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,563858367,1557275,16324 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,563183487,1546065,17587 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,584776808,1606426,15363 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,6006 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,710503156,1977117,16251 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,544801917,1496135,14923 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,544127037,1484925,16008 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,575503778,1574464,14251 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,4894 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,538948209,1492884,16317 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,537274225,1483290,16318 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,550162170,1515696,16318 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,519891759,1431744,14916 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,518217775,1422150,14917 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,531105720,1454556,14917 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,6006 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,4894 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,584776808,1606426,15363 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15755485,47872,6006 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,575503778,1574464,14251 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,80911114,217260,4894 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/forget to mint GATs/proposal,544127037,1484925,15362 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,544127037,1484925,16008 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,4894 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,544127037,1484925,16040 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs with bad token name/authority,12079326,37748,4926 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/proposal,544127037,1484925,16002 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/authority,80911114,217260,4888 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/proposal,544127037,1484925,16008 -Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/authority,80911114,217260,4894 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,682420527,1932425,15866 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,290118343,804775,13174 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,304223007,833517,14437 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,436427516,1189828,13263 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3906 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,678609237,1920197,15587 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,286307053,792547,12894 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,300411717,821289,13978 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,434172938,1182322,12897 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3540 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,279987729,780336,13167 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,278313745,770742,13168 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,291201690,803148,13168 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,276176439,768108,12887 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,274502455,758514,12888 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,287390400,790920,12888 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3906 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3540 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,436427516,1189828,13263 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3906 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,434172938,1182322,12897 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3540 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/forget to mint GATs/proposal,300411717,821289,13333 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,300411717,821289,13978 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3540 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,300411717,821289,14010 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3572 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/proposal,300411717,821289,13972 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/authority,80911114,217260,3534 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/proposal,300411717,821289,13978 -Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/authority,80911114,217260,3540 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,756645247,2136727,16782 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,368037949,1019065,14089 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,378447727,1037819,15352 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,478162744,1307060,13873 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,4516 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,749022667,2112271,16222 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,360415369,994609,13530 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,370825147,1013363,14614 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,474153553,1293440,13321 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3964 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,354212449,984638,14082 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,352538465,975044,14083 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,365426410,1007450,14083 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,346589869,960182,13523 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,344915885,950588,13524 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,357803830,982994,13524 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,4516 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3964 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,478162744,1307060,13873 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15755485,47872,4516 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,474153553,1293440,13321 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3964 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/forget to mint GATs/proposal,370825147,1013363,13968 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,370825147,1013363,14614 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3964 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,370825147,1013363,14646 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3996 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/proposal,370825147,1013363,14608 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/authority,80911114,217260,3958 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/proposal,370825147,1013363,14614 -Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/authority,80911114,217260,3964 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,979319407,2749633,19529 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,601796767,1661935,16836 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,601121887,1650725,18099 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,603368428,1658756,15704 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,6347 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,960262957,2688493,18128 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,582740317,1600795,15436 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,582065437,1589585,16520 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,594095398,1626794,14592 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,5235 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,576886609,1597544,16829 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,575212625,1587950,16830 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,588100570,1620356,16830 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,557830159,1536404,15429 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,556156175,1526810,15430 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,569044120,1559216,15430 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,6347 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,5235 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,603368428,1658756,15704 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15755485,47872,6347 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,594095398,1626794,14592 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,80911114,217260,5235 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/forget to mint GATs/proposal,582065437,1589585,15874 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,582065437,1589585,16520 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,5235 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,582065437,1589585,16552 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs with bad token name/authority,12079326,37748,5267 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/proposal,582065437,1589585,16514 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/authority,80911114,217260,5229 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/proposal,582065437,1589585,16520 -Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/authority,80911114,217260,5235 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/stake,147337981,392782,6702 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/proposal,248777421,680471,12017 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/stake,153687199,410890,6718 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/proposal,266163719,729912,12028 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/stake,146299704,389984,6700 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/proposal,237150672,650439,12014 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/stake,150455953,401836,6716 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/proposal,245388141,674947,12026 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/stake,147337981,392782,6706 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/proposal,233077780,642214,12021 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/stake,147337981,392782,6706 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/proposal,233643269,643416,12021 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/stake,153687199,410890,6722 -Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/proposal,251029567,692857,12032 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/stake,294042173,755738,9003 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/proposal,384044641,1002847,14294 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/stake,325788263,846278,9079 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/proposal,453034171,1203600,14345 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/stake,288850788,741748,8993 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/proposal,358441456,945903,14287 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/stake,309632033,801008,9073 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/proposal,396633649,1057259,14339 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/stake,294042173,755738,9023 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/proposal,358521672,948870,14314 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/stake,294042173,755738,9023 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/proposal,359087161,950072,14314 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/stake,325788263,846278,9099 -Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/proposal,428076691,1150825,14365 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/stake,477422413,1209433,11879 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/proposal,553128666,1405817,17140 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/stake,540914593,1390513,12030 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/proposal,686622236,1795710,17241 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/stake,467039643,1181453,11859 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/proposal,510054936,1315233,17128 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/stake,508602133,1299973,12019 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/proposal,585690534,1535149,17230 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/stake,477422413,1209433,11919 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/proposal,515326537,1332190,17180 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/stake,477422413,1209433,11919 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/proposal,515892026,1333392,17180 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/stake,540914593,1390513,12070 -Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/proposal,649385596,1723285,17281 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/stake,1651055949,4113081,30401 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/proposal,1635266426,3984825,35451 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/stake,1917723105,4873617,31089 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/proposal,2181585852,5585214,35910 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/stake,1607448315,3995565,30317 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/proposal,1480381208,3678945,35407 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/stake,1782010773,4493349,31028 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/proposal,1795654598,4593645,35849 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/stake,1651055949,4113081,30570 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/proposal,1518877673,3785438,35620 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/stake,1651055949,4113081,30570 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/proposal,1519443162,3786640,35620 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/stake,1917723105,4873617,31258 -Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/proposal,2065762588,5387029,36079 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter , status: Draft/stake",147337981,392782,6702 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter , status: Locked/stake",147337981,392782,6702 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter , status: Finished/stake",147337981,392782,6702 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator , status: Draft/stake",144619286,391178,6704 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator , status: Locked/stake",144619286,391178,6704 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator , status: Finished/stake",144619286,391178,6704 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both , status: Draft/stake",153687199,410890,6718 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both , status: Locked/stake",153687199,410890,6718 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both , status: Finished/stake",153687199,410890,6718 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",138270068,373070,6684 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",138270068,373070,6684 -"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,138270068,373070,6684 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Draft/stake,146299704,389984,6700 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: VotingReady/stake,146299704,389984,6700 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Locked/stake,146299704,389984,6700 -Agora/Proposal/validator/unlocking/illegal/with 1 proposals/creator: retract votes/stake,146299704,389984,6698 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter , status: Draft/stake",294042173,755738,9003 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter , status: Locked/stake",294042173,755738,9003 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter , status: Finished/stake",294042173,755738,9003 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator , status: Draft/stake",290272026,763438,9009 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator , status: Locked/stake",290272026,763438,9009 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator , status: Finished/stake",290272026,763438,9009 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both , status: Draft/stake",325788263,846278,9079 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both , status: Locked/stake",325788263,846278,9079 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both , status: Finished/stake",325788263,846278,9079 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",258525936,672898,8920 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",258525936,672898,8920 -"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,258525936,672898,8920 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Draft/stake,288850788,741748,8993 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: VotingReady/stake,288850788,741748,8993 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Locked/stake,288850788,741748,8993 -Agora/Proposal/validator/unlocking/illegal/with 5 proposals/creator: retract votes/stake,288850788,741748,8982 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter , status: Draft/stake",477422413,1209433,11879 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter , status: Locked/stake",477422413,1209433,11879 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter , status: Finished/stake",477422413,1209433,11879 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator , status: Draft/stake",472337951,1228763,11890 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator , status: Locked/stake",472337951,1228763,11890 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator , status: Finished/stake",472337951,1228763,11890 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both , status: Draft/stake",540914593,1390513,12030 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both , status: Locked/stake",540914593,1390513,12030 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both , status: Finished/stake",540914593,1390513,12030 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",408845771,1047683,11716 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",408845771,1047683,11716 -"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,408845771,1047683,11716 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Draft/stake,467039643,1181453,11859 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: VotingReady/stake,467039643,1181453,11859 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Locked/stake,467039643,1181453,11859 -Agora/Proposal/validator/unlocking/illegal/with 10 proposals/creator: retract votes/stake,467039643,1181453,11839 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter , status: Draft/stake",1651055949,4113081,30401 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter , status: Locked/stake",1651055949,4113081,30401 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter , status: Finished/stake",1651055949,4113081,30401 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator , status: Draft/stake",1637559871,4206843,30463 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator , status: Locked/stake",1637559871,4206843,30463 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator , status: Finished/stake",1637559871,4206843,30463 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both , status: Draft/stake",1917723105,4873617,31089 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both , status: Locked/stake",1917723105,4873617,31089 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both , status: Finished/stake",1917723105,4873617,31089 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",1370892715,3446307,29688 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",1370892715,3446307,29688 -"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,1370892715,3446307,29688 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Draft/stake,1607448315,3995565,30317 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: VotingReady/stake,1607448315,3995565,30317 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Locked/stake,1607448315,3995565,30317 -Agora/Proposal/validator/unlocking/illegal/with 42 proposals/creator: retract votes/stake,1607448315,3995565,30233 +Agora/Stake/validator/stakeDepositWithdraw deposit,131776572,375179,7328 +Agora/Stake/validator/stakeDepositWithdraw withdraw,131776572,375179,7320 +Agora/Stake/validator/set delegate/override existing delegate,155110062,435004,7459 +Agora/Stake/validator/set delegate/remove existing delegate,145775066,411616,7389 +Agora/Stake/validator/set delegate/set delegate to something,152681074,427904,7389 +Agora/Proposal/policy (proposal creation)/legal/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/legal/governor,275969940,726895,11606 +Agora/Proposal/policy (proposal creation)/legal/stake,285591523,773491,8105 +Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/stake,285591523,773491,8105 +Agora/Proposal/policy (proposal creation)/illegal/use other's stake/proposal,34052826,101718,2009 +Agora/Proposal/policy (proposal creation)/illegal/use other's stake/governor,275969940,726895,11575 +Agora/Proposal/policy (proposal creation)/illegal/altered stake/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/proposal,34052826,101718,2048 +Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/governor,275969940,726895,11614 +Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/proposal,34052826,101718,2060 +Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/stake,298289959,809707,8136 +Agora/Proposal/policy (proposal creation)/illegal/loose time range/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/illegal/loose time range/stake,285591523,773491,8105 +Agora/Proposal/policy (proposal creation)/illegal/open time range/proposal,34052826,101718,2036 +Agora/Proposal/policy (proposal creation)/illegal/open time range/stake,285591523,773491,8101 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/stake,285591523,773491,8105 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/stake,285591523,773491,8105 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/proposal,34052826,101718,2040 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/stake,285591523,773491,8105 +Agora/Proposal/validator/cosignature/legal/with 1 cosigners: proposal,215479714,616586,11643 +Agora/Proposal/validator/cosignature/legal/with 5 cosigners: proposal,517656416,1429318,13008 +Agora/Proposal/validator/cosignature/legal/with 10 cosigners: proposal,999034382,2685005,14715 +Agora/Proposal/validator/voting/legal/different number of stakes/1 stakes/by owner/proposal,212972337,610304,11838 +Agora/Proposal/validator/voting/legal/different number of stakes/1 stakes/by owner/stake,250511654,706369,7814 +Agora/Proposal/validator/voting/legal/different number of stakes/1 stakes/by delegatee/proposal,212972337,610304,11838 +Agora/Proposal/validator/voting/legal/different number of stakes/1 stakes/by delegatee/stake,256935993,722124,7814 +Agora/Proposal/validator/voting/legal/different number of stakes/3 stakes/by owner/proposal,315681431,900960,13053 +Agora/Proposal/validator/voting/legal/different number of stakes/3 stakes/by owner/stake,498721508,1361509,9029 +Agora/Proposal/validator/voting/legal/different number of stakes/3 stakes/by delegatee/proposal,315681431,900960,13053 +Agora/Proposal/validator/voting/legal/different number of stakes/3 stakes/by delegatee/stake,505145847,1377264,9029 +Agora/Proposal/validator/voting/legal/different number of stakes/5 stakes/by owner/proposal,418390525,1191616,14268 +Agora/Proposal/validator/voting/legal/different number of stakes/5 stakes/by owner/stake,746931362,2016649,10244 +Agora/Proposal/validator/voting/legal/different number of stakes/5 stakes/by delegatee/proposal,418390525,1191616,14268 +Agora/Proposal/validator/voting/legal/different number of stakes/5 stakes/by delegatee/stake,753355701,2032404,10244 +Agora/Proposal/validator/voting/legal/different number of stakes/7 stakes/by owner/proposal,521099619,1482272,15482 +Agora/Proposal/validator/voting/legal/different number of stakes/7 stakes/by owner/stake,995141216,2671789,11458 +Agora/Proposal/validator/voting/legal/different number of stakes/7 stakes/by delegatee/proposal,521099619,1482272,15482 +Agora/Proposal/validator/voting/legal/different number of stakes/7 stakes/by delegatee/stake,1001565555,2687544,11458 +Agora/Proposal/validator/voting/legal/different number of stakes/9 stakes/by owner/proposal,623808713,1772928,16697 +Agora/Proposal/validator/voting/legal/different number of stakes/9 stakes/by owner/stake,1243351070,3326929,12673 +Agora/Proposal/validator/voting/legal/different number of stakes/9 stakes/by delegatee/proposal,623808713,1772928,16697 +Agora/Proposal/validator/voting/legal/different number of stakes/9 stakes/by delegatee/stake,1249775409,3342684,12673 +Agora/Proposal/validator/voting/legal/transparent non-GT tokens/proposal,212972337,610304,11838 +Agora/Proposal/validator/voting/legal/transparent non-GT tokens/stake,250511654,706369,7814 +Agora/Proposal/validator/voting/illegal/vote for nonexistent outcome/stake,250511654,706369,7819 +Agora/Proposal/validator/voting/illegal/unauthorized tx/proposal,212972337,610304,11838 +Agora/Proposal/validator/voting/illegal/more than one proposals/stake,250511654,706369,7819 +Agora/Proposal/validator/voting/illegal/locks not added/proposal,418390525,1191616,14237 +Agora/Proposal/validator/voting/illegal/attempt to burn stakes/proposal,395323670,1139996,13209 +Agora/Proposal/validator/voting/illegal/insufficient staked amount/stake,250511654,706369,7791 +Agora/Proposal/validator/voting/illegal/insufficient staked amount/stake,746931362,2016649,10156 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,241684860,684071,12452 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,222017687,620605,12215 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,236122351,649347,13482 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,397042799,1075492,12619 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3299 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,237873570,671843,12173 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,218206397,608377,11936 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,232311061,637119,13024 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,394788221,1067986,12254 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,2934 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,211887073,596166,12208 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,210213089,586572,12209 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,223101034,618978,12209 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,208075783,583938,11929 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,206401799,574344,11930 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,219289744,606750,11930 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3299 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,2934 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,397042799,1075492,12619 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3299 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,394788221,1067986,12254 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,80911114,217260,2934 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/forget to mint GATs/proposal,232311061,637119,12378 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,232311061,637119,13024 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,2934 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,232311061,637119,13056 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs with bad token name/authority,12079326,37748,2966 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/proposal,232311061,637119,13018 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/authority,80911114,217260,2928 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/proposal,232311061,637119,13024 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/authority,80911114,217260,2934 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,315909580,888373,13368 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,299937293,834895,13131 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,310347071,853649,14398 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,438778027,1192724,13230 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3910 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,308287000,863917,12807 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,292314713,810439,12570 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,302724491,829193,13659 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,434768836,1179104,12678 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3358 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,286111793,800468,13124 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,284437809,790874,13125 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,297325754,823280,13125 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,278489213,776012,12563 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,276815229,766418,12564 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,289703174,798824,12564 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3910 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3358 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,438778027,1192724,13230 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3910 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,434768836,1179104,12678 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3358 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/forget to mint GATs/proposal,302724491,829193,13013 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,302724491,829193,13659 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3358 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,302724491,829193,13691 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3390 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/proposal,302724491,829193,13653 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/authority,80911114,217260,3352 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/proposal,302724491,829193,13659 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/authority,80911114,217260,3358 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,538583740,1501279,16115 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,533696111,1477765,15878 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,533021231,1466555,17145 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,563983711,1544420,15061 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,5741 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,519527290,1440139,14714 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,514639661,1416625,14477 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,513964781,1405415,15566 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,554710681,1512458,13949 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,4629 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,508785953,1413374,15871 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,507111969,1403780,15872 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,519999914,1436186,15872 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,489729503,1352234,14470 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,488055519,1342640,14471 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,500943464,1375046,14471 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,5741 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,4629 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,563983711,1544420,15061 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15755485,47872,5741 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,554710681,1512458,13949 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,80911114,217260,4629 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/forget to mint GATs/proposal,513964781,1405415,14920 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,513964781,1405415,15566 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,4629 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,513964781,1405415,15598 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs with bad token name/authority,12079326,37748,4661 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/proposal,513964781,1405415,15560 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/authority,80911114,217260,4623 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/proposal,513964781,1405415,15566 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/authority,80911114,217260,4629 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,417970750,1190555,13953 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,252368407,704333,12625 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,266473071,733075,13892 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,411916095,1117356,12892 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3572 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,414159460,1178327,13672 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,248557117,692105,12345 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,262661781,720847,13433 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,409661517,1109850,12527 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3207 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,242237793,679894,12618 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,240563809,670300,12619 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,253451754,702706,12619 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,238426503,667666,12338 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,236752519,658072,12339 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,249640464,690478,12339 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3572 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3207 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,411916095,1117356,12892 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3572 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,409661517,1109850,12527 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3207 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/forget to mint GATs/proposal,262661781,720847,12787 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,262661781,720847,13433 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3207 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,262661781,720847,13465 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3239 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/proposal,262661781,720847,13427 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/authority,80911114,217260,3201 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/proposal,262661781,720847,13433 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/authority,80911114,217260,3207 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,492195470,1394857,14868 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,330288013,918623,13541 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,340697791,937377,14808 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,453651323,1234588,13503 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,4183 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,484572890,1370401,14308 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,322665433,894167,12980 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,333075211,912921,14069 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,449642132,1220968,12951 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3631 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,316462513,884196,13534 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,314788529,874602,13535 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,327676474,907008,13535 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,308839933,859740,12973 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,307165949,850146,12974 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,320053894,882552,12974 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,4183 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3631 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,453651323,1234588,13503 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15755485,47872,4183 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,449642132,1220968,12951 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3631 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/forget to mint GATs/proposal,333075211,912921,13423 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,333075211,912921,14069 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3631 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,333075211,912921,14101 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3663 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/proposal,333075211,912921,14063 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/authority,80911114,217260,3625 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/proposal,333075211,912921,14069 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/authority,80911114,217260,3631 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,714869630,2007763,17614 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,564046831,1561493,16287 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,563371951,1550283,17554 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,578857007,1586284,15334 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,6014 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,695813180,1946623,16214 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,544990381,1500353,14886 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,544315501,1489143,15975 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,569583977,1554322,14222 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,4902 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,539136673,1497102,16280 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,537462689,1487508,16281 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,550350634,1519914,16281 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,520080223,1435962,14879 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,518406239,1426368,14880 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,531294184,1458774,14880 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,6014 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,4902 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,578857007,1586284,15334 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15755485,47872,6014 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,569583977,1554322,14222 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,80911114,217260,4902 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/forget to mint GATs/proposal,544315501,1489143,15329 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,544315501,1489143,15975 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,4902 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,544315501,1489143,16007 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs with bad token name/authority,12079326,37748,4934 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/proposal,544315501,1489143,15969 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/authority,80911114,217260,4896 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/proposal,544315501,1489143,15975 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/authority,80911114,217260,4902 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,653491556,1869351,15829 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,290306807,808993,13137 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,304411471,837735,14404 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,430507715,1169686,13234 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,3914 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,649680266,1857123,15550 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,286495517,796765,12857 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,300600181,825507,13945 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,428253137,1162180,12868 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3548 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,280176193,784554,13130 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,278502209,774960,13131 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,291390154,807366,13131 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,276364903,772326,12850 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,274690919,762732,12851 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,287578864,795138,12851 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,3914 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3548 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,430507715,1169686,13234 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15755485,47872,3914 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,428253137,1162180,12868 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3548 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/forget to mint GATs/proposal,300600181,825507,13300 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,300600181,825507,13945 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3548 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,300600181,825507,13977 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs with bad token name/authority,12079326,37748,3580 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/proposal,300600181,825507,13939 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/authority,80911114,217260,3542 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/proposal,300600181,825507,13945 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/authority,80911114,217260,3548 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,727716276,2073653,16745 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,368226413,1023283,14052 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,378636191,1042037,15319 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,472242943,1286918,13844 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,4524 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,720093696,2049197,16185 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,360603833,998827,13493 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,371013611,1017581,14581 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,468233752,1273298,13292 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,3972 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,354400913,988856,14045 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,352726929,979262,14046 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,365614874,1011668,14046 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,346778333,964400,13486 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,345104349,954806,13487 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,357992294,987212,13487 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,4524 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,3972 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,472242943,1286918,13844 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15755485,47872,4524 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,468233752,1273298,13292 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,80911114,217260,3972 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/forget to mint GATs/proposal,371013611,1017581,13935 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,371013611,1017581,14581 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,3972 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,371013611,1017581,14613 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs with bad token name/authority,12079326,37748,4004 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/proposal,371013611,1017581,14575 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/authority,80911114,217260,3966 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/proposal,371013611,1017581,14581 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/authority,80911114,217260,3972 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,950390436,2686559,19492 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,601985231,1666153,16799 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,601310351,1654943,18066 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,597448627,1638614,15675 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15755485,47872,6355 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,931333986,2625419,18091 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,582928781,1605013,15399 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,582253901,1593803,16487 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,588175597,1606652,14563 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,80911114,217260,5243 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,577075073,1601762,16792 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,575401089,1592168,16793 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,588289034,1624574,16793 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,558018623,1540622,15392 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,556344639,1531028,15393 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,569232584,1563434,15393 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15755485,47872,6355 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,80911114,217260,5243 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,597448627,1638614,15675 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15755485,47872,6355 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,588175597,1606652,14563 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,80911114,217260,5243 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/forget to mint GATs/proposal,582253901,1593803,15841 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,582253901,1593803,16487 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,80911114,217260,5243 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,582253901,1593803,16519 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs with bad token name/authority,12079326,37748,5275 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/proposal,582253901,1593803,16481 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/authority,80911114,217260,5237 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/proposal,582253901,1593803,16487 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/authority,80911114,217260,5243 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/voter: retract votes while voting/stake,261437934,715948,8036 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/voter: retract votes while voting/proposal,210078186,594774,12065 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/voter: retract votes while voting by delegatee/stake,267862273,731703,8036 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/voter: retract votes while voting by delegatee/proposal,210078186,594774,12065 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/voter/creator: retract votes while voting/stake,270958650,743485,8052 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/voter/creator: retract votes while voting/proposal,216873590,615188,12076 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/creator: remove creator lock after voting/stake,261933191,716955,8039 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/creator: remove creator lock after voting/proposal,181968899,516983,12069 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/Voter: remove lock after voting/stake,262568912,718352,8041 +Agora/Proposal/validator/unlocking/legal/with 1 stakes/Voter: remove lock after voting/proposal,183007176,519781,12070 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/voter: retract votes while voting/stake,530554502,1381974,9381 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/voter: retract votes while voting/proposal,316741456,889978,13410 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/voter: retract votes while voting by delegatee/stake,536978841,1397729,9381 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/voter: retract votes while voting by delegatee/proposal,316741456,889978,13410 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/voter/creator: retract votes while voting/stake,559116650,1464585,9419 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/voter/creator: retract votes while voting/proposal,337127668,951220,13443 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/creator: remove creator lock after voting/stake,529778317,1380187,9382 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/creator: remove creator lock after voting/proposal,247894061,696527,13412 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/Voter: remove lock after voting/stake,531685480,1384378,9386 +Agora/Proposal/validator/unlocking/legal/with 3 stakes/Voter: remove lock after voting/proposal,251008892,704921,13415 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/voter: retract votes while voting/stake,819317726,2079440,10727 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/voter: retract votes while voting/proposal,423404726,1185182,14756 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/voter: retract votes while voting by delegatee/stake,825742065,2095195,10727 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/voter: retract votes while voting by delegatee/proposal,423404726,1185182,14756 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/voter/creator: retract votes while voting/stake,866921306,2217125,10787 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/voter/creator: retract votes while voting/proposal,457381746,1287252,14811 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/creator: remove creator lock after voting/stake,817270099,2074859,10726 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/creator: remove creator lock after voting/proposal,313819223,876071,14756 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/Voter: remove lock after voting/stake,820448704,2081844,10732 +Agora/Proposal/validator/unlocking/legal/with 5 stakes/Voter: remove lock after voting/proposal,319010608,890061,14761 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/voter: retract votes while voting/stake,1127727606,2808346,12072 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/voter: retract votes while voting/proposal,530067996,1480386,16101 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/voter: retract votes while voting by delegatee/stake,1134151945,2824101,12072 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/voter: retract votes while voting by delegatee/proposal,530067996,1480386,16101 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/voter/creator: retract votes while voting/stake,1194372618,3001105,12154 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/voter/creator: retract votes while voting/proposal,577635824,1623284,16178 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/creator: remove creator lock after voting/stake,1124408537,2800971,12069 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/creator: remove creator lock after voting/proposal,379744385,1055615,16099 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/Voter: remove lock after voting/stake,1128858584,2810750,12077 +Agora/Proposal/validator/unlocking/legal/with 7 stakes/Voter: remove lock after voting/proposal,387012324,1075201,16106 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/voter: retract votes while voting/stake,1455784142,3568692,13417 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/voter: retract votes while voting/proposal,636731266,1775590,17446 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/voter: retract votes while voting by delegatee/stake,1462208481,3584447,13417 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/voter: retract votes while voting by delegatee/proposal,636731266,1775590,17446 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/voter/creator: retract votes while voting/stake,1541470586,3816525,13521 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/voter/creator: retract votes while voting/proposal,697889902,1959316,17545 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/creator: remove creator lock after voting/stake,1451193631,3558523,13412 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/creator: remove creator lock after voting/proposal,445669547,1235159,17442 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/Voter: remove lock after voting/stake,1456915120,3571096,13422 +Agora/Proposal/validator/unlocking/legal/with 9 stakes/Voter: remove lock after voting/proposal,455014040,1260341,17451 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/voter: retract votes while voting/stake,1803487334,4360478,14763 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/voter: retract votes while voting/proposal,743394536,2070794,18792 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/voter: retract votes while voting by delegatee/stake,1809911673,4376233,14763 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/voter: retract votes while voting by delegatee/proposal,743394536,2070794,18792 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/voter/creator: retract votes while voting/stake,1908215210,4663385,14890 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/voter/creator: retract votes while voting/proposal,818143980,2295348,18914 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/creator: remove creator lock after voting/stake,1797625381,4347515,14756 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/creator: remove creator lock after voting/proposal,511594709,1414703,18786 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/Voter: remove lock after voting/stake,1804618312,4362882,14768 +Agora/Proposal/validator/unlocking/legal/with 11 stakes/Voter: remove lock after voting/proposal,523015756,1445481,18797 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/retract votes while not voting/(negative test)/stake,260872445,714746,8036 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/retract votes while not voting/(negative test)/stake,262003423,717150,8036 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/retract votes while not voting/(negative test)/stake,262568912,718352,8036 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/remove creator too early/(negative test)/proposal,180272432,513377,12069 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/remove creator too early/(negative test)/proposal,184477283,524638,12069 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/remove creator too early/(negative test)/proposal,181403410,515781,12069 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/unlock an irrelevant stake/stake,270536932,747909,8058 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/creator: retract votes/stake,258799749,715312,8040 +Agora/Proposal/validator/unlocking/illegal/with 1 stakes/change output stake value/proposal,210078186,594774,12062 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/retract votes while not voting/(negative test)/stake,529989013,1380772,9381 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/retract votes while not voting/(negative test)/stake,531119991,1383176,9381 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/retract votes while not voting/(negative test)/stake,531685480,1384378,9381 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/remove creator too early/(negative test)/proposal,246197594,692921,13412 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/remove creator too early/(negative test)/proposal,250402445,704182,13412 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/remove creator too early/(negative test)/proposal,247328572,695325,13412 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/unlock an irrelevant stake/stake,543116504,1454277,9437 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/creator: retract votes/stake,507904955,1356486,9395 +Agora/Proposal/validator/unlocking/illegal/with 3 stakes/change output stake value/proposal,316741456,889978,13401 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/retract votes while not voting/(negative test)/stake,818752237,2078238,10727 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/retract votes while not voting/(negative test)/stake,819883215,2080642,10727 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/retract votes while not voting/(negative test)/stake,820448704,2081844,10727 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/remove creator too early/(negative test)/proposal,312122756,872465,14756 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/remove creator too early/(negative test)/proposal,316327607,883726,14756 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/remove creator too early/(negative test)/proposal,313253734,874869,14756 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/unlock an irrelevant stake/stake,815696076,2160645,10817 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/creator: retract votes/stake,757010161,1997660,10751 +Agora/Proposal/validator/unlocking/illegal/with 5 stakes/change output stake value/proposal,423404726,1185182,14740 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/retract votes while not voting/(negative test)/stake,1127162117,2807144,12072 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/retract votes while not voting/(negative test)/stake,1128293095,2809548,12072 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/retract votes while not voting/(negative test)/stake,1128858584,2810750,12072 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/remove creator too early/(negative test)/proposal,378047918,1052009,16099 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/remove creator too early/(negative test)/proposal,382252769,1063270,16099 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/remove creator too early/(negative test)/proposal,379178896,1054413,16099 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/unlock an irrelevant stake/stake,1088275648,2867013,12196 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/creator: retract votes/stake,1006115367,2638834,12106 +Agora/Proposal/validator/unlocking/illegal/with 7 stakes/change output stake value/proposal,530067996,1480386,16080 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/retract votes while not voting/(negative test)/stake,1455218653,3567490,13417 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/retract votes while not voting/(negative test)/stake,1456349631,3569894,13417 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/retract votes while not voting/(negative test)/stake,1456915120,3571096,13417 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/remove creator too early/(negative test)/proposal,443973080,1231553,17442 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/remove creator too early/(negative test)/proposal,448177931,1242814,17442 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/remove creator too early/(negative test)/proposal,445104058,1233957,17442 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/unlock an irrelevant stake/stake,1360855220,3573381,13576 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/creator: retract votes/stake,1255220573,3280008,13461 +Agora/Proposal/validator/unlocking/illegal/with 9 stakes/change output stake value/proposal,636731266,1775590,17419 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/retract votes while not voting/(negative test)/stake,1802921845,4359276,14763 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/retract votes while not voting/(negative test)/stake,1804052823,4361680,14763 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/retract votes while not voting/(negative test)/stake,1804618312,4362882,14763 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/remove creator too early/(negative test)/proposal,509898242,1411097,18786 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/remove creator too early/(negative test)/proposal,514103093,1422358,18786 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/remove creator too early/(negative test)/proposal,511029220,1413501,18786 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/unlock an irrelevant stake/stake,1633434792,4279749,14956 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/creator: retract votes/stake,1504325779,3921182,14818 +Agora/Proposal/validator/unlocking/illegal/with 11 stakes/change output stake value/proposal,743394536,2070794,18759 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,26456223,75851,755 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,51581175,146321,855 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct even though scripts don't match,26456223,75851,754 @@ -478,5 +465,5 @@ Agora/Treasury/Validator/Positive/Fails when GAT token name is not script addres Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,26456223,75851,755 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,51581175,146321,855 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct even though scripts don't match,26456223,75851,754 -Agora/Governor/policy/totally legal,59844630,160840,2585 -Agora/Governor/validator/mutate/legal,124803201,345777,11001 +Agora/Governor/policy/totally legal,61478715,165435,2674 +Agora/Governor/validator/mutate/legal,126634074,350768,10968 diff --git a/flake.lock b/flake.lock index 0a1bfd8..bdcc464 100644 --- a/flake.lock +++ b/flake.lock @@ -11460,11 +11460,11 @@ "plutarch": "plutarch_6" }, "locked": { - "lastModified": 1663679353, - "narHash": "sha256-CK+hgOoU9qARRnaUlxlh9ZBWb0G6d8F0VslAbXd8mIM=", + "lastModified": 1664495234, + "narHash": "sha256-GEl2kRkL3MdHL1fDKbur5VVThR/w082w7KccfDL42qg=", "owner": "Liqwid-Labs", "repo": "plutarch-context-builder", - "rev": "3bc59acb11264c4fa43c95fa615a4dbf69e0f981", + "rev": "9ea4dab758a4d60e69c794fe4e349ddabc8e7018", "type": "github" }, "original": { @@ -11979,17 +11979,17 @@ "plutarch": "plutarch_15" }, "locked": { - "lastModified": 1664028810, + "lastModified": 1664220695, "narHash": "sha256-thMEO1P/ciHjnMFyL0bla781TG5C/nB5EEtebb3Boik=", "owner": "Liqwid-Labs", "repo": "plutarch-script-export", - "rev": "4f0da58ba67cdcfe5c7d97e6e27dc00dfb71e657", + "rev": "eba175e63516a4fed43ceab1826ea6522f28dd0f", "type": "github" }, "original": { "owner": "Liqwid-Labs", + "ref": "main", "repo": "plutarch-script-export", - "rev": "4f0da58ba67cdcfe5c7d97e6e27dc00dfb71e657", "type": "github" } },