Merge pull request #142 from Liqwid-Labs/connor/fix-proposal-creation

Fix proposal creation
This commit is contained in:
Emily 2022-07-13 11:34:40 +02:00 committed by GitHub
commit 9f2066d138
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 1720 additions and 664 deletions

View file

@ -106,7 +106,7 @@ governorDatumValidProperty =
thres <- genProposalThresholds c
let timing = ProposalTimingConfig 0 0 0 0
return $ GovernorDatum thres (ProposalId 0) timing (MaxTimeRangeWidth 0)
return $ GovernorDatum thres (ProposalId 0) timing (MaxTimeRangeWidth 0) 3
where
taggedInteger p = Tagged <$> chooseInteger p
genProposalThresholds :: GovernorDatumCases -> Gen ProposalThresholds
@ -181,6 +181,7 @@ governorMintingProperty =
, nextProposalId = ProposalId 0
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
gen :: GovernorPolicyCases -> Gen ScriptContext

View file

@ -106,6 +106,7 @@ mkEffectTxInfo newGovDatum =
, nextProposalId = ProposalId 0
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
governorInputDatum :: Datum
governorInputDatum = Datum $ toBuiltinData governorInputDatum'
@ -168,6 +169,7 @@ validNewGovernorDatum =
, nextProposalId = ProposalId 42
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
invalidNewGovernorDatum :: GovernorDatum
@ -180,4 +182,5 @@ invalidNewGovernorDatum =
, nextProposalId = ProposalId 42
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}

View file

@ -1,5 +1,5 @@
{- |
Module : Spec.Sample.Governor
Module : Sample.Governor
Maintainer : connor@mlabs.city
Description: Sample based testing for Governor utxos
@ -119,6 +119,7 @@ mintGST =
, nextProposalId = ProposalId 0
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
witness :: ValidatorHash
@ -183,6 +184,7 @@ createProposal =
, nextProposalId = thisProposalId
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
effects =
@ -216,8 +218,7 @@ createProposal =
proposalLocks :: [ProposalLock]
proposalLocks =
[ ProposalLock (ResultTag 0) thisProposalId
, ProposalLock (ResultTag 1) thisProposalId
[ Created thisProposalId
]
stakeOutputDatum :: StakeDatum
stakeOutputDatum = stakeInputDatum {lockedBy = proposalLocks}
@ -304,6 +305,7 @@ mintGATs =
, nextProposalId = ProposalId 5
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
effects =
@ -423,6 +425,7 @@ mutateState =
, nextProposalId = ProposalId 5
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = 3
}
governorOutputDatum :: GovernorDatum

View file

@ -1,114 +0,0 @@
{- |
Module : Sample.Proposal
Maintainer : emi@haskell.fyi
Description: Sample based testing for Proposal utxos
This module tests primarily the happy path for Proposal interactions
-}
module Sample.Proposal (
-- * Script contexts
proposalCreation,
) where
import Agora.Governor (GovernorDatum (..))
import Agora.Proposal (
Proposal (..),
ProposalDatum (..),
ProposalId (..),
ProposalStatus (..),
ResultTag (..),
emptyVotesFor,
)
import Data.Default.Class (Default (def))
import Plutarch.Context (
MintingBuilder,
buildMintingUnsafe,
input,
mint,
output,
script,
signedWith,
txId,
withDatum,
withTxId,
withValue,
)
import PlutusLedgerApi.V1 (
ScriptContext (..),
)
import PlutusLedgerApi.V1.Value qualified as Value (
assetClassValue,
singleton,
)
import PlutusTx.AssocMap qualified as AssocMap
import Sample.Shared (
govValidatorHash,
proposal,
proposalPolicySymbol,
proposalStartingTimeFromTimeRange,
proposalValidatorHash,
signer,
)
import Test.Util (
closedBoundedInterval,
)
proposalCreation :: ScriptContext
proposalCreation =
let st = Value.singleton proposalPolicySymbol "" 1 -- Proposal ST
effects =
AssocMap.fromList
[ (ResultTag 0, AssocMap.empty)
, (ResultTag 1, AssocMap.empty)
]
proposalDatum :: ProposalDatum
proposalDatum =
ProposalDatum
{ proposalId = ProposalId 0
, effects = effects
, status = Draft
, cosigners = [signer]
, thresholds = def
, votes = emptyVotesFor effects
, timingConfig = def
, startingTime = proposalStartingTimeFromTimeRange validTimeRange
}
govBefore :: GovernorDatum
govBefore =
GovernorDatum
{ proposalThresholds = def
, nextProposalId = ProposalId 0
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
}
govAfter :: GovernorDatum
govAfter = govBefore {nextProposalId = ProposalId 1}
validTimeRange = closedBoundedInterval 10 15
builder :: MintingBuilder
builder =
mconcat
[ txId "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be"
, signedWith signer
, mint st
, input $
script govValidatorHash
. withValue (Value.assetClassValue proposal.governorSTAssetClass 1)
. withDatum govBefore
. withTxId "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be"
, output $
script proposalValidatorHash
. withValue (st <> Value.singleton "" "" 10_000_000)
. withDatum proposalDatum
, output $
script govValidatorHash
. withValue
( Value.assetClassValue proposal.governorSTAssetClass 1
<> Value.singleton "" "" 10_000_000
)
. withDatum govAfter
]
in buildMintingUnsafe builder

View file

@ -1,3 +1,10 @@
{- |
Module : Sample.Proposal.Advance
Maintainer : connor@mlabs.city
Description: Generate sample data for testing the functionalities of advancing proposals
Sample and utilities for testing the functionalities of advancing proposals.
-}
module Sample.Proposal.Advance (
advanceToNextStateInTimeParameters,
advanceToFailedStateDueToTimeoutParameters,
@ -31,7 +38,7 @@ import Agora.Proposal.Time (
)
import Agora.SafeMoney (GTTag)
import Agora.Stake (
ProposalLock (ProposalLock),
ProposalLock (..),
Stake (gtClassRef),
StakeDatum (..),
StakeRedeemer (WitnessStake),
@ -69,7 +76,7 @@ import PlutusLedgerApi.V1 (
)
import PlutusLedgerApi.V1.Value qualified as Value
import PlutusTx.AssocMap qualified as AssocMap
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef, testFunc)
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef)
import Sample.Shared (
minAda,
proposalPolicySymbol,
@ -79,7 +86,7 @@ import Sample.Shared (
stakeValidatorHash,
)
import Sample.Shared qualified as Shared
import Test.Specification (SpecificationTree, group)
import Test.Specification (SpecificationTree, group, testValidator)
import Test.Util (closedBoundedInterval, pubKeyHashes, sortValue, updateMap)
-- | Parameters for state transition of proposals.
@ -99,19 +106,24 @@ data Parameters = Parameters
, stakeCount :: Integer
-- ^ The number of stakes.
, signByAllCosigners :: Bool
-- ^ Whether the transaction is signed by all the cosigners.
, perStakeGTs :: Tagged GTTag Integer
-- ^ The staked amount of each stake.
}
---
-- | Reference to the proposal UTXO.
proposalRef :: TxOutRef
proposalRef = TxOutRef proposalTxRef 1
-- | Create the reference to a particular stake UTXO.
mkStakeRef :: Int -> TxOutRef
mkStakeRef = TxOutRef stakeTxRef . (+ 2) . fromIntegral
---
-- | Default effects of the propsoal.
defEffects :: AssocMap.Map ResultTag (AssocMap.Map ValidatorHash DatumHash)
defEffects =
AssocMap.fromList
@ -119,14 +131,19 @@ defEffects =
, (ResultTag 1, AssocMap.empty)
]
-- | Empty votes for the default effects.
emptyVotes :: ProposalVotes
emptyVotes = emptyVotesFor defEffects
{- | The default proposal statring time, which doesn't really matter in this
case.
-}
proposalStartingTime :: POSIXTime
proposalStartingTime = 0
---
-- | Create the input proposal datum given the parameters.
mkProposalInputDatum :: Parameters -> ProposalDatum
mkProposalInputDatum ps =
ProposalDatum
@ -140,6 +157,7 @@ mkProposalInputDatum ps =
, startingTime = ProposalStartingTime proposalStartingTime
}
-- | Create the input stake datums given the parameters.
mkStakeInputDatums :: Parameters -> [StakeDatum]
mkStakeInputDatums ps =
map
@ -154,28 +172,37 @@ mkStakeInputDatums ps =
where
existingLocks :: [ProposalLock]
existingLocks =
[ ProposalLock (ResultTag 0) (ProposalId 0)
, ProposalLock (ResultTag 2) (ProposalId 1)
[ Voted (ProposalId 0) (ResultTag 0)
, Voted (ProposalId 1) (ResultTag 2)
]
---
-- | Script purpose of the proposal validator.
proposalScriptPurpose :: ScriptPurpose
proposalScriptPurpose = Spending proposalRef
-- | Script purpose of the stake validator, given which stake we want to spend.
mkStakeScriptPurpose :: Int -> ScriptPurpose
mkStakeScriptPurpose = Spending . mkStakeRef
---
{- | The propsoal redeemer used to spend the proposal UTXO, which is always
'AdvanceProposal' in this case.
-}
proposalRedeemer :: ProposalRedeemer
proposalRedeemer = AdvanceProposal
{- | The propsoal redeemer used to spend the stake UTXO, which is always
'WitnessStake' in this case.
-}
stakeRedeemer :: StakeRedeemer
stakeRedeemer = WitnessStake
---
-- | Create some valid stake owners.
mkStakeOwners :: Parameters -> [PubKeyHash]
mkStakeOwners ps =
sort $
@ -276,6 +303,9 @@ advance ps =
---
{- | Given the proposal status, create a time range that is in time for
advacing to the next state.
-}
mkInTimeTimeRange :: ProposalStatus -> POSIXTimeRange
mkInTimeTimeRange advanceFrom =
case advanceFrom of
@ -315,6 +345,9 @@ mkInTimeTimeRange advanceFrom =
)
Finished -> error "Cannot advance 'Finished' proposal"
{- | Given the proposal status, create a time range that is too time for
advacing to the next state.
-}
mkTooLateTimeRange :: ProposalStatus -> POSIXTimeRange
mkTooLateTimeRange advanceFrom =
case advanceFrom of
@ -363,6 +396,7 @@ mkTooLateTimeRange advanceFrom =
---
-- | Next state of the given proposal status.
getNextState :: ProposalStatus -> ProposalStatus
getNextState = \case
Draft -> VotingReady
@ -475,6 +509,9 @@ invalidOutputStakeParameters nCosigners =
---
{- | Create a test tree that runs the stake validator and proposal validator to
test the advancing functionalities.
-}
mkTestTree :: String -> Parameters -> Bool -> SpecificationTree
mkTestTree name ps isValidForProposalValidator = group name [proposal, stake]
where
@ -482,7 +519,7 @@ mkTestTree name ps isValidForProposalValidator = group name [proposal, stake]
proposal =
let proposalInputDatum = mkProposalInputDatum ps
in testFunc
in testValidator
isValidForProposalValidator
"propsoal"
(proposalValidator Shared.proposal)
@ -497,7 +534,7 @@ mkTestTree name ps isValidForProposalValidator = group name [proposal, stake]
let idx = 0
stakeInputDatum = mkStakeInputDatums ps !! idx
isValid = not $ ps.alterOutputStakes
in testFunc
in testValidator
isValid
"stake"
(stakeValidator Shared.stake)

View file

@ -1,3 +1,10 @@
{- |
Module : Sample.Proposal.Cosign
Maintainer : connor@mlabs.city
Description: Generate sample data for testing the functionalities of cosigning proposals
Sample and utilities for testing the functionalities of cosigning proposals.
-}
module Sample.Proposal.Cosign (
Parameters (..),
validCosignNParameters,
@ -57,7 +64,7 @@ import PlutusLedgerApi.V1 (
)
import PlutusLedgerApi.V1.Value qualified as Value
import PlutusTx.AssocMap qualified as AssocMap
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef, testFunc)
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef)
import Sample.Shared (
minAda,
proposalPolicySymbol,
@ -71,6 +78,7 @@ import Sample.Shared qualified as Shared
import Test.Specification (
SpecificationTree,
group,
testValidator,
)
import Test.Util (closedBoundedInterval, pubKeyHashes, sortValue)
@ -317,7 +325,7 @@ mkTestTree name ps isValid = group name [proposal, stake]
proposal =
let proposalInputDatum = mkProposalInputDatum ps
in testFunc
in testValidator
isValid
"propsoal"
(proposalValidator Shared.proposal)
@ -332,7 +340,7 @@ mkTestTree name ps isValid = group name [proposal, stake]
let idx = 0
stakeInputDatum = mkStakeInputDatums ps !! idx
isValid = not ps.alterOutputStakes
in testFunc
in testValidator
isValid
"stake"
(stakeValidator Shared.stake)

View file

@ -0,0 +1,461 @@
{- |
Module : Sample.Proposal.Create
Maintainer : connor@mlabs.city
Description: Generate sample data for testing the functionalities of creating proposals
Sample and utilities for testing the functionalities of creating proposals.
-}
module Sample.Proposal.Create (
Parameters (..),
mkTestTree,
totallyValidParameters,
invalidOutputGovernorDatumParameters,
useStakeOwnBySomeoneElseParameters,
invalidOutputStakeParameters,
addInvalidLocksParameters,
exceedMaximumProposalsParameters,
timeRangeNotTightParameters,
timeRangeNotClosedParameters,
invalidProposalStatusParameters,
) where
import Agora.Governor (
GovernorDatum (..),
GovernorRedeemer (CreateProposal),
)
import Agora.Governor.Scripts (governorValidator)
import Agora.Proposal (
Proposal (governorSTAssetClass),
ProposalDatum (..),
ProposalId (ProposalId),
ProposalStatus (..),
ResultTag (ResultTag),
emptyVotesFor,
)
import Agora.Proposal.Scripts (proposalPolicy)
import Agora.Proposal.Time (MaxTimeRangeWidth (MaxTimeRangeWidth), ProposalStartingTime (..))
import Agora.Stake (
ProposalLock (..),
Stake (gtClassRef),
StakeDatum (..),
StakeRedeemer (PermitVote),
)
import Agora.Stake.Scripts (stakeValidator)
import Data.Coerce (coerce)
import Data.Default (Default (def))
import Data.Tagged (Tagged, untag)
import Plutarch.Context (
BaseBuilder,
buildTxInfoUnsafe,
input,
mint,
output,
script,
signedWith,
timeRange,
txId,
withDatum,
withOutRef,
withValue,
)
import PlutusLedgerApi.V1 (
DatumHash,
POSIXTime (POSIXTime),
POSIXTimeRange,
PubKeyHash,
ScriptContext (ScriptContext),
ScriptPurpose (Minting, Spending),
TxInfo,
TxOutRef (TxOutRef),
ValidatorHash,
always,
)
import PlutusLedgerApi.V1.Value qualified as Value
import PlutusTx.AssocMap qualified as AssocMap
import Sample.Proposal.Shared (stakeTxRef)
import Sample.Shared (
govValidatorHash,
minAda,
proposal,
proposalPolicySymbol,
proposalStartingTimeFromTimeRange,
proposalValidatorHash,
signer,
signer2,
stake,
stakeAssetClass,
stakeValidatorHash,
)
import Sample.Shared qualified as Shared
import Test.Specification (SpecificationTree, group, testPolicy, testValidator)
import Test.Util (closedBoundedInterval, sortValue)
-- | Parameters for creating a proposal.
data Parameters = Parameters
{ advanceNextProposalId :: Bool
-- ^ Whether to advance 'GovernorDatum.nextProposalId'.
, createdMoreThanMaximumProposals :: Bool
-- ^ Try creating more than maximum amount of proposals.
, stakeOwnerSignsTheTransaction :: Bool
-- ^ Should the stake owner sign the transaction?
, invalidNewLocks :: Bool
-- ^ Place invalid new locks on the output stake.
, alterOutputStakeOwner :: Bool
-- ^ Whether to change the 'owner' field of the output stake datum.
, timeRangeTightEnough :: Bool
-- ^ Is 'TxInfo.validTimeRange' tight enough?
, timeRangeClosed :: Bool
-- ^ Is 'TxInfo.validTimeRange' closed?
, proposalStatus :: ProposalStatus
-- ^ The status of the newly created proposal.
}
--------------------------------------------------------------------------------
-- | See 'GovernorDatum.maximumProposalsPerStake'.
maxProposalPerStake :: Integer
maxProposalPerStake = 3
-- | The id of the proposal we are creating.
thisProposalId :: ProposalId
thisProposalId = ProposalId 25
-- | The arbitrary staked amount. Doesn;t really matter in this case.
stakedGTs :: Tagged _ Integer
stakedGTs = 5
-- | The owner of the stake.
stakeOwner :: PubKeyHash
stakeOwner = signer
{- | The invalid stake owner. If the 'alterOutputStakeOwner' is set to true,
the output stake owner will be set to this.
-}
alteredStakeOwner :: PubKeyHash
alteredStakeOwner = signer2
-- | Locks the stake that the input stake already has.
defLocks :: [ProposalLock]
defLocks = [Created (ProposalId 0)]
-- | The effect of the newly created proposal.
defEffects :: AssocMap.Map ResultTag (AssocMap.Map ValidatorHash DatumHash)
defEffects =
AssocMap.fromList
[ (ResultTag 0, AssocMap.empty)
, (ResultTag 1, AssocMap.empty)
]
--------------------------------------------------------------------------------
-- | The governor input datum.
governorInputDatum :: GovernorDatum
governorInputDatum =
GovernorDatum
{ proposalThresholds = def
, nextProposalId = thisProposalId
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = maxProposalPerStake
}
-- | Create governor output datum given the parameters.
mkGovernorOutputDatum :: Parameters -> GovernorDatum
mkGovernorOutputDatum ps =
let nextPid =
if ps.advanceNextProposalId
then ProposalId $ coerce thisProposalId + 1
else thisProposalId
in GovernorDatum
{ proposalThresholds = def
, nextProposalId = nextPid
, proposalTimings = def
, createProposalTimeRangeMaxWidth = def
, maximumProposalsPerStake = maxProposalPerStake
}
--------------------------------------------------------------------------------
-- | Create the stake input datum given the parameters.
mkStakeInputDatum :: Parameters -> StakeDatum
mkStakeInputDatum ps =
let locks =
if ps.createdMoreThanMaximumProposals
then
Created . ProposalId
<$> take
(fromInteger maxProposalPerStake)
[1 ..]
else defLocks
in StakeDatum
{ stakedAmount = stakedGTs
, owner = stakeOwner
, lockedBy = locks
}
-- | Create the stake output datum given the parameters.
mkStakeOutputDatum :: Parameters -> StakeDatum
mkStakeOutputDatum ps =
let inputDatum = mkStakeInputDatum ps
newLocks =
if ps.invalidNewLocks
then
[ Voted thisProposalId (ResultTag 0)
, Voted thisProposalId (ResultTag 1)
]
else [Created thisProposalId]
locks = newLocks <> inputDatum.lockedBy
newOwner = mkOwner ps
in inputDatum
{ owner = newOwner
, lockedBy = locks
}
--------------------------------------------------------------------------------
{- | Create the proposal datum for the newly created proposal, given the
parameters.
-}
mkProposalOutputDatum :: Parameters -> ProposalDatum
mkProposalOutputDatum ps =
ProposalDatum
{ proposalId = thisProposalId
, effects = defEffects
, status = ps.proposalStatus
, cosigners = [mkOwner ps]
, thresholds = def
, votes = emptyVotesFor defEffects
, timingConfig = def
, startingTime = mkProposalStartingTime ps
}
--------------------------------------------------------------------------------
-- | Create time range for 'TxInfo.validTimeRange'.
mkTimeRange :: Parameters -> POSIXTimeRange
mkTimeRange ps =
if ps.timeRangeClosed
then
let s = 0
di :: POSIXTime = coerce (def @MaxTimeRangeWidth)
o = if ps.timeRangeTightEnough then (-1) else 1
in closedBoundedInterval s $ o + di
else always
-- | Get the starting time of the propsoal.
mkProposalStartingTime :: Parameters -> ProposalStartingTime
mkProposalStartingTime ps =
if ps.timeRangeClosed
then proposalStartingTimeFromTimeRange $ mkTimeRange ps
else ProposalStartingTime 0
-- | Who should be the 'owner' of the output stake.
mkOwner :: Parameters -> PubKeyHash
mkOwner ps =
if ps.alterOutputStakeOwner
then alteredStakeOwner
else stakeOwner
--------------------------------------------------------------------------------
-- | Reference to the input stake UTXO.
stakeRef :: TxOutRef
stakeRef = TxOutRef stakeTxRef 1
-- | Reference to the input governor UTXO.
governorRef :: TxOutRef
governorRef = TxOutRef "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be" 3
--------------------------------------------------------------------------------
-- | Create a 'TxInfo' that spends a stake to create a new proposal.
createProposal :: Parameters -> TxInfo
createProposal ps = buildTxInfoUnsafe builder
where
pst = Value.singleton proposalPolicySymbol "" 1
sst = Value.assetClassValue stakeAssetClass 1
gst = Value.assetClassValue proposal.governorSTAssetClass 1
---
governorValue = sortValue $ gst <> minAda
stakeValue =
sortValue $
sortValue $
sst
<> Value.assetClassValue (untag stake.gtClassRef) (untag stakedGTs)
<> minAda
proposalValue = sortValue $ pst <> minAda
---
withSig =
if ps.stakeOwnerSignsTheTransaction
then signedWith stakeOwner
else mempty
---
builder :: BaseBuilder
builder =
mconcat
[ txId "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be"
, ---
withSig
, ---
mint pst
, ---
timeRange $ mkTimeRange ps
, input $
script govValidatorHash
. withValue governorValue
. withDatum governorInputDatum
. withOutRef governorRef
, output $
script govValidatorHash
. withValue governorValue
. withDatum (mkGovernorOutputDatum ps)
, ---
input $
script stakeValidatorHash
. withValue stakeValue
. withDatum (mkStakeInputDatum ps)
. withOutRef stakeRef
, output $
script stakeValidatorHash
. withValue stakeValue
. withDatum (mkStakeOutputDatum ps)
, ---
output $
script proposalValidatorHash
. withValue proposalValue
. withDatum (mkProposalOutputDatum ps)
]
--------------------------------------------------------------------------------
-- | Spend the stake with the 'PermitVote' redeemer.
stakeRedeemer :: StakeRedeemer
stakeRedeemer = PermitVote
-- | Spend the governor with the 'CreateProposal' redeemer.
governorRedeemer :: GovernorRedeemer
governorRedeemer = CreateProposal
-- | Mint the PST with an arbitrary redeemer. Doesn't really matter.
proposalPolicyRedeemer :: ()
proposalPolicyRedeemer = ()
--------------------------------------------------------------------------------
totallyValidParameters :: Parameters
totallyValidParameters =
Parameters
{ advanceNextProposalId = True
, createdMoreThanMaximumProposals = False
, stakeOwnerSignsTheTransaction = True
, invalidNewLocks = False
, alterOutputStakeOwner = False
, timeRangeTightEnough = True
, timeRangeClosed = True
, proposalStatus = Draft
}
invalidOutputGovernorDatumParameters :: Parameters
invalidOutputGovernorDatumParameters =
totallyValidParameters
{ advanceNextProposalId = False
}
useStakeOwnBySomeoneElseParameters :: Parameters
useStakeOwnBySomeoneElseParameters =
totallyValidParameters
{ stakeOwnerSignsTheTransaction = False
}
invalidOutputStakeParameters :: Parameters
invalidOutputStakeParameters =
totallyValidParameters
{ alterOutputStakeOwner = True
}
addInvalidLocksParameters :: Parameters
addInvalidLocksParameters =
totallyValidParameters
{ invalidNewLocks = True
}
exceedMaximumProposalsParameters :: Parameters
exceedMaximumProposalsParameters =
totallyValidParameters
{ createdMoreThanMaximumProposals = True
}
timeRangeNotTightParameters :: Parameters
timeRangeNotTightParameters =
totallyValidParameters
{ timeRangeTightEnough = False
}
timeRangeNotClosedParameters :: Parameters
timeRangeNotClosedParameters =
totallyValidParameters
{ timeRangeClosed = False
}
invalidProposalStatusParameters :: [Parameters]
invalidProposalStatusParameters =
map
( \st ->
totallyValidParameters {proposalStatus = st}
)
[VotingReady, Locked, Finished]
--------------------------------------------------------------------------------
{- | Create a test tree that runs the propsoal minting policy, the governor
validator and the stake validator to test the functionalities of creting
proposals
-}
mkTestTree :: String -> Parameters -> Bool -> Bool -> Bool -> SpecificationTree
mkTestTree
name
ps
validForProposalPolicy
validForGovernorValidator
validForStakeValidator =
group name [proposalTest, governorTest, stakeTest]
where
txInfo = createProposal ps
proposalTest =
testPolicy
validForProposalPolicy
"proposal"
(proposalPolicy Shared.proposal.governorSTAssetClass)
proposalPolicyRedeemer
(ScriptContext txInfo (Minting proposalPolicySymbol))
governorTest =
testValidator
validForGovernorValidator
"governor"
(governorValidator Shared.governor)
governorInputDatum
governorRedeemer
( ScriptContext
txInfo
(Spending governorRef)
)
stakeTest =
testValidator
validForStakeValidator
"stake"
(stakeValidator Shared.stake)
(mkStakeInputDatum ps)
stakeRedeemer
( ScriptContext
txInfo
(Spending stakeRef)
)

View file

@ -1,13 +1,13 @@
module Sample.Proposal.Shared (proposalTxRef, stakeTxRef, testFunc) where
{- |
Module : Sample.Proposal.Shared
Maintainer : connor@mlabs.city
Description: Shared constants for propsoal samples
import Plutarch.Api.V1 (PValidator)
import Plutarch.Lift (PUnsafeLiftDecl (..))
import PlutusLedgerApi.V1 (ScriptContext, ToData, TxId)
import Test.Specification (
SpecificationTree,
validatorFailsWith,
validatorSucceedsWith,
)
Shared constants for propsoal samples.
-}
module Sample.Proposal.Shared (proposalTxRef, stakeTxRef) where
import PlutusLedgerApi.V1 (TxId)
-- | 'TxId' of all the propsoal inputs in the samples.
proposalTxRef :: TxId
@ -16,24 +16,3 @@ proposalTxRef = "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be"
-- | 'TxId' of all the stake inputs in the samples.
stakeTxRef :: TxId
stakeTxRef = "0ca36f3a357bc69579ab2531aecd1e7d3714d993c7820f40b864be15"
-- | Get the test function given whether a test case is valid.
testFunc ::
forall {datum :: PType} {redeemer :: PType}.
( PUnsafeLiftDecl datum
, PUnsafeLiftDecl redeemer
, ToData (PLifted datum)
, ToData (PLifted redeemer)
) =>
-- | Should the validator pass?
Bool ->
String ->
ClosedTerm PValidator ->
PLifted datum ->
PLifted redeemer ->
ScriptContext ->
SpecificationTree
testFunc isValid =
if isValid
then validatorSucceedsWith
else validatorFailsWith

View file

@ -1,12 +1,26 @@
{- |
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 (
unlockStake,
StakeRole (..),
UnlockStakeParameters (..),
votesTemplate,
emptyEffectFor,
mkProposalInputDatum,
mkStakeInputDatum,
mkProposalValidatorTestCase,
Parameters (..),
unlockStake,
mkTestTree,
mkVoterRetractVotesWhileVotingParameters,
mkVoterCreatorRetractVotesWhileVotingParameters,
mkCreatorRemoveCreatorLocksWhenFinishedParameters,
mkVoterCreatorRemoveAllLocksWhenFinishedParameters,
mkVoterUnlockStakeAfterVotingParameters,
mkVoterCreatorRemoveVoteLocksWhenLockedParameters,
mkRetractVotesWhileNotVoting,
mkUnockIrrelevantStakeParameters,
mkRemoveCreatorLockBeforeFinishedParameters,
mkRetractVotesWithCreatorStakeParamaters,
mkAlterStakeParameters,
) where
--------------------------------------------------------------------------------
@ -21,9 +35,8 @@ import Agora.Proposal (
)
import Agora.Proposal.Scripts (proposalValidator)
import Agora.Proposal.Time (ProposalStartingTime (ProposalStartingTime))
import Agora.Stake (ProposalLock (ProposalLock), Stake (..), StakeDatum (..))
import Control.Monad (join)
import Data.Coerce (coerce)
import Agora.Stake (ProposalLock (..), Stake (..), StakeDatum (..), StakeRedeemer (RetractVotes))
import Agora.Stake.Scripts (stakeValidator)
import Data.Default.Class (Default (def))
import Data.Tagged (Tagged (..), untag)
import Plutarch.Context (
@ -32,14 +45,15 @@ import Plutarch.Context (
input,
output,
script,
signedWith,
txId,
withDatum,
withRefIndex,
withTxId,
withOutRef,
withValue,
)
import PlutusLedgerApi.V1 (
DatumHash,
PubKeyHash,
ScriptContext (..),
ScriptPurpose (Spending),
TxInfo (..),
@ -48,7 +62,7 @@ import PlutusLedgerApi.V1 (
)
import PlutusLedgerApi.V1.Value qualified as Value
import PlutusTx.AssocMap qualified as AssocMap
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef, testFunc)
import Sample.Proposal.Shared (stakeTxRef)
import Sample.Shared (
minAda,
proposalPolicySymbol,
@ -59,7 +73,7 @@ import Sample.Shared (
stakeValidatorHash,
)
import Sample.Shared qualified as Shared
import Test.Specification (SpecificationTree)
import Test.Specification (SpecificationTree, group, testValidator)
import Test.Util (sortValue, updateMap)
--------------------------------------------------------------------------------
@ -82,106 +96,130 @@ emptyEffectFor (ProposalVotes vs) =
map (,AssocMap.empty) (AssocMap.keys vs)
-- | The default vote option that will be used by functions in this module.
defaultVoteFor :: ResultTag
defaultVoteFor = ResultTag 0
defVoteFor :: ResultTag
defVoteFor = ResultTag 0
-- | The default number of GTs the stake will have.
defaultStakedGTs :: Tagged _ Integer
defaultStakedGTs = Tagged 100000
defStakedGTs :: Tagged _ Integer
defStakedGTs = 100000
{- | If 'Parameters.alterOutputStake' is set to true, the
'StakeDatum.stakedAmount' will be set to this.
-}
alteredStakedGTs :: Tagged _ Integer
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 created the proposal.
| -- | 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 UnlockStakeParameters = UnlockStakeParameters
data Parameters = Parameters
{ proposalCount :: Integer
-- ^ The number of proposals in the 'TxOut'.
, stakeUsage :: StakeRole
, 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
}
instance Show UnlockStakeParameters where
show p =
let role = case p.stakeUsage of
Voter -> "voter"
Creator -> "creator"
_ -> "irrelevant stake"
-- | 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]
action =
if p.retractVotes
then "unlock stake + retract votes"
else "unlock stake"
-- | 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
_ -> []
while = show p.proposalStatus
-- | 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
proposalInfo = mconcat [show p.proposalCount, " proposals"]
in mconcat [proposalInfo, ", ", role, ", ", action, ", ", while]
-- | Create the stake input datum given the parameters.
mkStakeInputDatum :: Parameters -> StakeDatum
mkStakeInputDatum ps =
StakeDatum
{ stakedAmount = defStakedGTs
, owner = defOwner
, 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 :: UnlockStakeParameters -> [(ProposalDatum, ProposalDatum)]
mkProposals p = forEachProposalId p.proposalCount $ mkProposalDatumPair p
-- | Iterate over the proposal id of every proposal, given the number of proposals.
forEachProposalId :: Integer -> (ProposalId -> a) -> [a]
forEachProposalId 0 _ = error "zero proposal"
forEachProposalId n f = f . ProposalId <$> [0 .. n - 1]
-- | Create the input stake and its corresponding output stake.
mkStakeDatumPair :: UnlockStakeParameters -> (StakeDatum, StakeDatum)
mkStakeDatumPair c =
let output =
StakeDatum
{ stakedAmount = defaultStakedGTs
, owner = signer
, lockedBy = []
}
inputLocks = join $ forEachProposalId c.proposalCount (mkStakeLocks c.stakeUsage)
input = output {lockedBy = inputLocks}
in (input, output)
where
mkStakeLocks :: StakeRole -> ProposalId -> [ProposalLock]
mkStakeLocks Voter pid = [ProposalLock defaultVoteFor pid]
mkStakeLocks Creator pid =
map (`ProposalLock` pid) $
AssocMap.keys $ getProposalVotes votesTemplate
mkStakeLocks _ _ = []
mkProposals :: Parameters -> [(ProposalDatum, ProposalDatum)]
mkProposals ps = forEachProposalId ps $ mkProposalDatumPair ps
-- | Create the input proposal datum.
mkProposalInputDatum :: UnlockStakeParameters -> ProposalId -> ProposalDatum
mkProposalInputDatum :: Parameters -> ProposalId -> ProposalDatum
mkProposalInputDatum p pid = fst $ mkProposalDatumPair p pid
-- | Create the input stake datum.
mkStakeInputDatum :: UnlockStakeParameters -> StakeDatum
mkStakeInputDatum = fst . mkStakeDatumPair
-- | Create a input proposal and its corresponding output proposal.
mkProposalDatumPair ::
UnlockStakeParameters ->
Parameters ->
ProposalId ->
(ProposalDatum, ProposalDatum)
mkProposalDatumPair params pid =
let owner = signer
inputVotes = mkInputVotes params.stakeUsage $ untag defaultStakedGTs
let inputVotes = mkInputVotes params.stakeRole $ untag defStakedGTs
input =
ProposalDatum
{ proposalId = pid
, effects = emptyEffectFor votesTemplate
, status = params.proposalStatus
, cosigners = [owner]
, cosigners = [defOwner]
, thresholds = def
, votes = inputVotes
, timingConfig = def
@ -200,62 +238,62 @@ mkProposalDatumPair params pid =
-- The staked amount/votes.
Integer ->
ProposalVotes
mkInputVotes Voter vc =
ProposalVotes $
updateMap (Just . const vc) defaultVoteFor $
getProposalVotes votesTemplate
mkInputVotes Creator _ =
ProposalVotes $
updateMap (Just . const 1000) defaultVoteFor $
updateMap (Just . const 1000) defVoteFor $
getProposalVotes votesTemplate
mkInputVotes Irrelevant _ = votesTemplate
mkInputVotes _ vc =
ProposalVotes $
updateMap (Just . const vc) defVoteFor $
getProposalVotes votesTemplate
mkInputVotes _ _ = votesTemplate
-- | Create a 'TxInfo' that tries to unlock a stake.
unlockStake :: UnlockStakeParameters -> TxInfo
unlockStake p =
unlockStake :: Parameters -> TxInfo
unlockStake ps =
let pst = Value.singleton proposalPolicySymbol "" 1
sst = Value.assetClassValue stakeAssetClass 1
pIODatums = mkProposals p
(sInDatum, sOutDatum) = mkStakeDatumPair p
pIODatums = mkProposals ps
proposals =
foldMap
( \(i, o) ->
( \((i, o), idx) ->
mconcat
@BaseBuilder
[ input $
script proposalValidatorHash
. withValue pst
. withDatum i
. withTxId proposalTxRef
. withRefIndex (coerce i.proposalId + 2)
. withOutRef (mkProposalRef idx)
, output $
script proposalValidatorHash
. withValue (sortValue $ pst <> minAda)
. withDatum o
]
)
pIODatums
(zip pIODatums [0 ..])
stakeValue =
sortValue $
mconcat
[ Value.assetClassValue
(untag stake.gtClassRef)
(untag defaultStakedGTs)
(untag defStakedGTs)
, sst
, minAda
]
sInDatum = mkStakeInputDatum ps
sOutDatum = mkStakeOutputDatum ps
stakes =
mconcat @BaseBuilder
[ input $
script stakeValidatorHash
. withValue stakeValue
. withDatum sInDatum
. withTxId stakeTxRef
. withRefIndex 1
. withOutRef stakeRef
, output $
script stakeValidatorHash
. withValue stakeValue
@ -267,23 +305,243 @@ unlockStake p =
[ txId "388bc0b897b3dadcd479da4c88291de4113a50b72ddbed001faf7fc03f11bc52"
, proposals
, stakes
, signedWith defOwner
]
in buildTxInfoUnsafe builder
-- | Create a test case that tests the proposal validator's @'Unlock' _@ redeemer.
mkProposalValidatorTestCase :: UnlockStakeParameters -> Bool -> SpecificationTree
mkProposalValidatorTestCase p shouldSucceed =
let datum = mkProposalInputDatum p $ ProposalId 0
redeemer = Unlock (ResultTag 0)
name = show p
scriptContext =
ScriptContext
(unlockStake p)
(Spending (TxOutRef proposalTxRef 2))
in testFunc
shouldSucceed
name
(proposalValidator Shared.proposal)
datum
redeemer
scriptContext
-- | 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
txInfo = unlockStake ps
stake =
testValidator
(not ps.alterOutputStake)
"stake"
(stakeValidator Shared.stake)
(mkStakeInputDatum ps)
stakeRedeemer
(ScriptContext txInfo (Spending stakeRef))
proposal =
let idx = 0
pid = ProposalId $ fromIntegral idx
ref = mkProposalRef idx
in testValidator
isValid
"propsoal"
(proposalValidator Shared.proposal)
(mkProposalInputDatum ps pid)
proposalRedeemer
(ScriptContext txInfo (Spending ref))

View file

@ -1,3 +1,10 @@
{- |
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,
mkTestTree,
@ -17,7 +24,7 @@ import Agora.Proposal.Time (
ProposalTimingConfig (draftTime, votingTime),
)
import Agora.Stake (
ProposalLock (ProposalLock),
ProposalLock (..),
Stake (gtClassRef),
StakeDatum (..),
StakeRedeemer (PermitVote),
@ -47,7 +54,7 @@ import PlutusLedgerApi.V1 (
)
import PlutusLedgerApi.V1.Value qualified as Value
import PlutusTx.AssocMap qualified as AssocMap
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef, testFunc)
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef)
import Sample.Shared (
minAda,
proposalPolicySymbol,
@ -61,13 +68,16 @@ import Sample.Shared qualified as Shared
import Test.Specification (
SpecificationTree,
group,
testValidator,
validatorSucceedsWith,
)
import Test.Util (closedBoundedInterval, sortValue, updateMap)
-- | Reference to the proposal UTXO.
proposalRef :: TxOutRef
proposalRef = TxOutRef proposalTxRef 0
-- | Reference to the stake UTXO.
stakeRef :: TxOutRef
stakeRef = TxOutRef stakeTxRef 1
@ -79,9 +89,11 @@ data Parameters = Parameters
-- ^ The count of votes.
}
-- | The public key hash of the stake owner.
stakeOwner :: PubKeyHash
stakeOwner = signer
-- | The votes of the input proposals.
initialVotes :: AssocMap.Map ResultTag Integer
initialVotes =
AssocMap.fromList
@ -89,6 +101,7 @@ initialVotes =
, (ResultTag 1, 4242)
]
-- | The input proposal datum.
proposalInputDatum :: ProposalDatum
proposalInputDatum =
ProposalDatum
@ -106,12 +119,16 @@ proposalInputDatum =
, startingTime = ProposalStartingTime 0
}
-- | The locks of the input stake.
existingLocks :: [ProposalLock]
existingLocks =
[ ProposalLock (ResultTag 0) (ProposalId 0)
, ProposalLock (ResultTag 2) (ProposalId 1)
[ Voted (ProposalId 0) (ResultTag 0)
, Voted (ProposalId 1) (ResultTag 2)
]
{- | Set the 'StakeDatum.stakedAmount' according to the number of votes being
casted.
-}
mkStakeInputDatum :: Parameters -> StakeDatum
mkStakeInputDatum params =
StakeDatum
@ -120,14 +137,19 @@ mkStakeInputDatum params =
, lockedBy = existingLocks
}
-- | Create the proposal redeemer. In this case @'Vote' _@ will always be used.
mkProposalRedeemer :: Parameters -> ProposalRedeemer
mkProposalRedeemer = Vote . voteFor
-- | Place new proposal locks on the stake.
mkNewLock :: Parameters -> ProposalLock
mkNewLock ps = ProposalLock ps.voteFor proposalInputDatum.proposalId
mkNewLock = Voted proposalInputDatum.proposalId . voteFor
mkStakeRedeemer :: Parameters -> StakeRedeemer
mkStakeRedeemer = PermitVote . mkNewLock
{- | 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 :: Parameters -> TxInfo
@ -210,6 +232,7 @@ vote params =
---
-- | Valida parameters that vote on the proposal.
validVoteParameters :: Parameters
validVoteParameters =
Parameters
@ -219,13 +242,16 @@ validVoteParameters =
---
{- | 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]
where
txInfo = vote ps
proposal =
testFunc
testValidator
isValid
"propsoal"
(proposalValidator Shared.proposal)
@ -242,7 +268,7 @@ mkTestTree name ps isValid = group name [proposal, stake]
"stake"
(stakeValidator Shared.stake)
stakeInputDatum
(mkStakeRedeemer ps)
stakeRedeemer
( ScriptContext
txInfo
(Spending stakeRef)

View file

@ -38,6 +38,7 @@ specs =
(ProposalId 0)
def
def
3
)
MutateGovernor
( ScriptContext
@ -60,6 +61,7 @@ specs =
(ProposalId 0)
def
def
3
)
MutateGovernor
( ScriptContext

View file

@ -47,6 +47,7 @@ specs =
(ProposalId 0)
def
def
3
)
CreateProposal
createProposal
@ -58,6 +59,7 @@ specs =
(ProposalId 5)
def
def
3
)
MintGATs
mintGATs
@ -69,6 +71,7 @@ specs =
(ProposalId 5)
def
def
3
)
MutateGovernor
mutateState

View file

@ -7,33 +7,83 @@ Tests for Proposal policy and validator
-}
module Spec.Proposal (specs) where
import Agora.Proposal (
Proposal (..),
ProposalStatus (..),
)
import Agora.Proposal.Scripts (proposalPolicy)
import Sample.Proposal qualified as Proposal
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.Vote qualified as Vote
import Sample.Shared qualified as Shared (proposal)
import Test.Specification (
SpecificationTree,
group,
policySucceedsWith,
)
-- | Stake specs.
specs :: [SpecificationTree]
specs =
[ group
"policy"
[ policySucceedsWith
"proposalCreation"
(proposalPolicy Shared.proposal.governorSTAssetClass)
()
Proposal.proposalCreation
"policy (proposal creation)"
[ Create.mkTestTree
"legal"
Create.totallyValidParameters
True
True
True
, group
"illegal"
[ Create.mkTestTree
"invalid next proposal id"
Create.invalidOutputGovernorDatumParameters
True
False
True
, Create.mkTestTree
"use other's stake"
Create.useStakeOwnBySomeoneElseParameters
True
False
False
, Create.mkTestTree
"altered stake"
Create.invalidOutputStakeParameters
True
False
False
, Create.mkTestTree
"invalid stake locks"
Create.addInvalidLocksParameters
True
False
True
, Create.mkTestTree
"has reached maximum proposals limit"
Create.exceedMaximumProposalsParameters
True
False
True
, Create.mkTestTree
"loose time range"
Create.timeRangeNotTightParameters
True
False
True
, Create.mkTestTree
"open time range"
Create.timeRangeNotClosedParameters
True
False
True
, group "invalid proposal status" $
map
( \ps ->
Create.mkTestTree
(show ps.proposalStatus)
ps
True
False
True
)
Create.invalidProposalStatusParameters
]
]
, group
"validator"
@ -166,110 +216,92 @@ specs =
pure $ Advance.mkTestTree name ps False
]
in [draftGroup, legalGroup, illegalGroup]
, group "unlocking" $ do
proposalCount <- [1, 42]
, group "unlocking" $
let proposalCountCases = [1, 5, 10, 42]
let legalGroup = group "legal" $ do
let voterRetractVotesAndUnlockStakeWhileVoting =
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Voter
, UnlockStake.retractVotes = True
, UnlockStake.proposalStatus = VotingReady
}
True
creatorUnlockStakeWhileFinished =
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Creator
, UnlockStake.retractVotes = False
, UnlockStake.proposalStatus = Finished
}
True
mkSubgroupName nProposals = "with " <> show nProposals <> " proposals"
let voterUnlockStakeAfterVoting = group "voter unlocks stake after voting" $ do
status <- [Finished, Locked]
pure $
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Voter
, UnlockStake.retractVotes = False
, UnlockStake.proposalStatus = status
}
True
[ voterRetractVotesAndUnlockStakeWhileVoting
, creatorUnlockStakeWhileFinished
, voterUnlockStakeAfterVoting
mkLegalGroup nProposals =
group
(mkSubgroupName nProposals)
[ UnlockStake.mkTestTree
"voter: retract votes while voting"
(UnlockStake.mkVoterRetractVotesWhileVotingParameters nProposals)
True
, UnlockStake.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
]
let illegalGroup = group "illegal" $ do
let retractsVotesWhileNotVotingReady =
group "voter retracts votes while not voting" $ do
status <- [Draft, Locked, Finished]
pure $
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Voter
, UnlockStake.retractVotes = True
, UnlockStake.proposalStatus = status
}
False
unlockIrrelevantStake =
group "unlock an irrelevant stake" $ do
status <- [Draft, VotingReady, Locked, Finished]
shouldRetractVotes <- [True, False]
pure $
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Irrelevant
, UnlockStake.retractVotes = shouldRetractVotes
, UnlockStake.proposalStatus = status
}
False
unlockCreatorStakeBeforeFinished =
group "unlock creator stake before finished" $ do
status <- [Draft, VotingReady, Locked]
pure $
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Creator
, UnlockStake.retractVotes = False
, UnlockStake.proposalStatus = status
}
False
retractVotesWithCreatorStake =
group "creator stake retracts votes" $ do
status <- [Draft, VotingReady, Locked, Finished]
pure $
UnlockStake.mkProposalValidatorTestCase
UnlockStake.UnlockStakeParameters
{ UnlockStake.proposalCount = proposalCount
, UnlockStake.stakeUsage = UnlockStake.Creator
, UnlockStake.retractVotes = True
, UnlockStake.proposalStatus = status
}
False
[ retractsVotesWhileNotVotingReady
, unlockIrrelevantStake
, unlockCreatorStakeBeforeFinished
, retractVotesWithCreatorStake
mkIllegalGroup nProposals =
group
(mkSubgroupName nProposals)
[ group "retract votes while not voting" $
map
( \ps ->
let name =
"role: " <> show ps.stakeRole
<> ", status: "
<> show ps.proposalStatus
in UnlockStake.mkTestTree name ps False
)
(UnlockStake.mkRetractVotesWhileNotVoting nProposals)
, group "unlock an irrelevant stake" $
map
( \ps ->
let name =
"status: " <> show ps.proposalStatus
<> "retract votes: "
<> show ps.retractVotes
in UnlockStake.mkTestTree name ps False
)
(UnlockStake.mkUnockIrrelevantStakeParameters nProposals)
, group "remove creator too early" $
map
( \ps ->
let name =
"status: " <> show ps.proposalStatus
in UnlockStake.mkTestTree name ps False
)
(UnlockStake.mkRemoveCreatorLockBeforeFinishedParameters nProposals)
, UnlockStake.mkTestTree
"creator: retract votes"
(UnlockStake.mkRetractVotesWithCreatorStakeParamaters nProposals)
False
, group "alter output stake datum" $
map
( \ps ->
let name =
"role: " <> show ps.stakeRole
<> ", status: "
<> show ps.proposalStatus
in UnlockStake.mkTestTree name ps False
)
(UnlockStake.mkAlterStakeParameters nProposals)
]
[legalGroup, illegalGroup]
legalGroup = group "legal" $ map mkLegalGroup proposalCountCases
illegalGroup = group "illegal" $ map mkIllegalGroup proposalCountCases
in [legalGroup, illegalGroup]
]
]

View file

@ -42,6 +42,8 @@ module Test.Specification (
validatorFailsWith,
effectSucceedsWith,
effectFailsWith,
testValidator,
testPolicy,
-- * Converters
toTestTree,
@ -253,3 +255,37 @@ effectFailsWith ::
ScriptContext ->
SpecificationTree
effectFailsWith tag eff datum = validatorFailsWith tag eff datum ()
testValidator ::
( PLift datum
, PlutusTx.ToData (PLifted datum)
, PLift redeemer
, PlutusTx.ToData (PLifted redeemer)
) =>
-- | Should the validator pass?
Bool ->
String ->
ClosedTerm PValidator ->
PLifted datum ->
PLifted redeemer ->
ScriptContext ->
SpecificationTree
testValidator isValid =
if isValid
then validatorSucceedsWith
else validatorFailsWith
testPolicy ::
( PLift redeemer
, PlutusTx.ToData (PLifted redeemer)
) =>
Bool ->
String ->
ClosedTerm PMintingPolicy ->
PLifted redeemer ->
ScriptContext ->
SpecificationTree
testPolicy isValid =
if isValid
then policySucceedsWith
else policyFailsWith

View file

@ -95,12 +95,16 @@ updateMap f k =
--------------------------------------------------------------------------------
-- | Sort the given 'AssocMap.Map' by keys in ascending order.
sortMap :: forall k v. Ord k => AssocMap.Map k v -> AssocMap.Map k v
sortMap =
AssocMap.fromList
. sortOn fst
. AssocMap.toList
{- | Sort the given 'Value' in ascending order. Some plutarch functions that
work with plutarch's 'Sorted' 'PMap' require this to work correctly.
-}
sortValue :: Value -> Value
sortValue =
Value

View file

@ -188,9 +188,9 @@ library agora-specs
Sample.Effect.GovernorMutation
Sample.Effect.TreasuryWithdrawal
Sample.Governor
Sample.Proposal
Sample.Proposal.Advance
Sample.Proposal.Cosign
Sample.Proposal.Create
Sample.Proposal.Shared
Sample.Proposal.UnlockStake
Sample.Proposal.Vote

View file

@ -73,6 +73,9 @@ data GovernorDatum = GovernorDatum
-- Will get copied over upon the creation of proposals.
, createProposalTimeRangeMaxWidth :: MaxTimeRangeWidth
-- ^ The maximum valid duration of a transaction that creats a proposal.
, maximumProposalsPerStake :: Integer
-- ^ The maximum number of unfinished proposals that a stake is allowed to be
-- associated to.
}
deriving stock (Show, GHC.Generic)
@ -149,6 +152,7 @@ newtype PGovernorDatum (s :: S) = PGovernorDatum
, "nextProposalId" ':= PProposalId
, "proposalTimings" ':= PProposalTimingConfig
, "createProposalTimeRangeMaxWidth" ':= PMaxTimeRangeWidth
, "maximumProposalsPerStake" ':= PInteger
]
)
}

View file

@ -46,8 +46,6 @@ import Agora.Governor (
)
import Agora.Proposal (
PProposalDatum (..),
PProposalId (..),
PResultTag,
Proposal (..),
ProposalStatus (Draft, Finished, Locked),
pemptyVotesFor,
@ -65,6 +63,7 @@ import Agora.Stake (
PProposalLock (..),
PStakeDatum (..),
Stake (..),
pnumCreatedProposals,
)
import Agora.Stake.Scripts (
stakePolicy,
@ -108,7 +107,6 @@ import Plutarch.Api.V1.ScriptContext (pfindTxInByTxOutRef, pisUTXOSpent, ptryFin
import "liqwid-plutarch-extra" Plutarch.Api.V1.Value (psymbolValueOf)
import Plutarch.Extra.IsData (pmatchEnumFromData)
import Plutarch.Extra.Map (
pkeys,
plookup,
plookup',
)
@ -300,6 +298,7 @@ governorValidator gov =
, "nextProposalId"
, "proposalTimings"
, "createProposalTimeRangeMaxWidth"
, "maximumProposalsPerStake"
]
oldGovernorDatum
@ -341,6 +340,8 @@ governorValidator gov =
.& #proposalTimings .= oldGovernorDatumF.proposalTimings
.& #createProposalTimeRangeMaxWidth
.= oldGovernorDatumF.createProposalTimeRangeMaxWidth
.& #maximumProposalsPerStake
.= oldGovernorDatumF.maximumProposalsPerStake
)
pguardC "Unexpected governor state datum" $
newGovernorDatum #== expectedNewDatum
@ -377,6 +378,10 @@ governorValidator gov =
stakeInputDatumF <-
pletFieldsC @["stakedAmount", "owner", "lockedBy"] stakeInputDatum
pguardC "Proposals created by the stake must not exceed the number stored in the governor." $
pnumCreatedProposals # stakeInputDatumF.lockedBy
#< oldGovernorDatumF.maximumProposalsPerStake
pguardC "Required amount of stake GTs should be presented" $
stakeInputDatumF.stakedAmount #== (pgtValueOf # stakeInputF.value)
@ -479,25 +484,14 @@ governorValidator gov =
mustBePJust # "Stake output not found" #$ ptryFindDatum # stakeOutputDatumHash # txInfoF.datums
-- The stake should be locked by the newly created proposal.
let possibleVoteResults = pkeys #$ pto $ pfromData proposalOutputDatum.votes
mkProposalLock :: Term _ (PProposalId :--> PAsData PResultTag :--> PAsData PProposalLock)
mkProposalLock =
phoistAcyclic $
plam
( \pid rt' ->
pdata $
mkRecordConstr
PProposalLock
( #vote .= rt' .& #proposalTag .= pdata pid
)
)
let newLock =
mkRecordConstr
PCreated
( #created .= oldGovernorDatumF.nextProposalId
)
-- Append new locks to existing locks
expectedProposalLocks =
pconcat # stakeInputDatumF.lockedBy
#$ pmap # (mkProposalLock # proposalOutputDatum.proposalId) # possibleVoteResults
expectedProposalLocks = pcons # pdata newLock # stakeInputDatumF.lockedBy
expectedStakeOutputDatum =
pdata $

View file

@ -68,6 +68,7 @@ import Plutarch.Lift (
PUnsafeLiftDecl (..),
)
import Plutarch.SafeMoney (PDiscrete)
import Plutarch.Show (PShow (..))
import PlutusLedgerApi.V1 (DatumHash, PubKeyHash, ValidatorHash)
import PlutusLedgerApi.V1.Value (AssetClass)
import PlutusTx qualified
@ -328,7 +329,7 @@ data ProposalRedeemer
-- This list should be sorted in ascending order.
Cosign [PubKeyHash]
| -- | Allow unlocking one or more stakes with votes towards particular 'ResultTag'.
Unlock ResultTag
Unlock
| -- | Advance the proposal, performing the required checks for whether that is legal.
--
-- These are roughly the checks for each possible transition:
@ -408,6 +409,8 @@ newtype PResultTag (s :: S) = PResultTag (Term s PInteger)
PEq
, -- | @since 0.1.0
POrd
, -- | @since 0.2.0
PShow
)
via (DerivePNewtype PResultTag PInteger)
@ -440,6 +443,8 @@ newtype PProposalId (s :: S) = PProposalId (Term s PInteger)
PEq
, -- | @since 0.1.0
POrd
, -- | @since 0.2.0
PShow
)
via (DerivePNewtype PProposalId PInteger)
@ -665,7 +670,7 @@ deriving via (DerivePConstantViaDataList ProposalDatum PProposalDatum) instance
data PProposalRedeemer (s :: S)
= PVote (Term s (PDataRecord '["resultTag" ':= PResultTag]))
| PCosign (Term s (PDataRecord '["newCosigners" ':= PBuiltinList (PAsData PPubKeyHash)]))
| PUnlock (Term s (PDataRecord '["resultTag" ':= PResultTag]))
| PUnlock (Term s (PDataRecord '[]))
| PAdvanceProposal (Term s (PDataRecord '[]))
deriving stock
( -- | @since 0.1.0

View file

@ -29,8 +29,12 @@ import Agora.Proposal.Time (
import Agora.Stake (
PProposalLock (..),
PStakeDatum (..),
PStakeUsage (..),
pgetStakeUsage,
pextractVoteOption,
pgetStakeRole,
pisCreator,
pisIrrelevant,
pisPureCreator,
pisVoter,
)
import Agora.Utils (
getMintingPolicySymbol,
@ -469,12 +473,7 @@ proposalValidator proposal =
-- 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 #$ pany
# plam
( \((pfield @"proposalTag" #) . pfromData -> pid) ->
pid #== proposalF.proposalId
)
# pfromData stakeInF.lockedBy
pnot #$ pisVoter #$ pgetStakeRole # proposalF.proposalId # pfromData 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.
@ -510,9 +509,9 @@ proposalValidator proposal =
let newProposalLock =
mkRecordConstr
PProposalLock
( #vote .= pdata voteFor
.& #proposalTag .= proposalF.proposalId
PVoted
( #votedOn .= proposalF.proposalId
.& #votedFor .= pdata voteFor
)
-- Prepend the new lock to existing locks
expectedProposalLocks =
@ -533,30 +532,12 @@ proposalValidator proposal =
----------------------------------------------------------------------
PUnlock r -> withSingleStake $ \stakeInF stakeOut _ -> do
-- At draft stage, the votes should be empty.
pguardC "Shouldn't retract votes from a draft proposal" $
pnot #$ currentStatus #== pconstant Draft
PUnlock _ -> withSingleStake $ \stakeInF stakeOut _ -> do
stakeRole <- pletC $ pgetStakeRole # proposalF.proposalId # stakeInF.lockedBy
-- This is the vote option we're retracting from.
retractFrom <- pletC $ pfield @"resultTag" # r
pguardC "Stake input should be relevant" $
pnot #$ pisIrrelevant # stakeRole
-- Determine if the input stake is actually locked by this proposal.
stakeUsage <- pletC $ pgetStakeUsage # stakeInF.lockedBy # proposalF.proposalId
pguardC "Stake input relevant" $
pmatch stakeUsage $ \case
PDidNothing ->
ptraceIfFalse "Stake should be relevant" $
pconstant False
PCreated ->
ptraceIfFalse "Removing creator's locks means status is Finished" $
currentStatus #== pconstant Finished
PVotedFor rt ->
ptraceIfFalse "Result tag should match the one given in the redeemer" $
rt #== retractFrom
-- The count of removing votes is equal to the 'stakeAmount' of input stake.
retractCount <-
pletC $
pmatch stakeInF.stakedAmount $ \(PDiscrete v) -> pextract # v
@ -564,13 +545,34 @@ proposalValidator proposal =
-- The votes can only change when the proposal still allows voting.
let shouldUpdateVotes =
currentStatus #== pconstant VotingReady
#&& pnot # (pcon PCreated #== stakeUsage)
#&& 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 # proposalF.proposalId # locks
)
$ \newStakeRole ->
pif
(isCreator #&& pnot # allowRemovingCreatorLock)
(pisPureCreator # newStakeRole)
(pisIrrelevant # newStakeRole)
pguardC "Proposal output correct" $
pif
shouldUpdateVotes
( let -- Remove votes and leave other parts of the proposal as it.
expectedVotes = pretractVotes # retractFrom # retractCount # proposalF.votes
expectedVotes = pretractVotes # (pextractVoteOption # stakeRole) # retractCount # proposalF.votes
expectedProposalOut =
mkRecordConstr
@ -598,15 +600,14 @@ proposalValidator proposal =
PStakeDatum
( #stakedAmount .= stakeInF.stakedAmount
.& #owner .= stakeInF.owner
.& #lockedBy .= stakeOutputLocks
.& #lockedBy .= pdata stakeOutputLocks
)
pguardC "Only locks updated in the output stake" $
templateStakeOut #== stakeOut
pguardC "All relevant locks removed from the stake" $
pgetStakeUsage # pfromData stakeOutputLocks
# proposalF.proposalId #== pcon PDidNothing
validateOutputLocks # stakeOutputLocks
pure $ pconstant ()

View file

@ -18,11 +18,17 @@ module Agora.Stake (
PStakeDatum (..),
PStakeRedeemer (..),
PProposalLock (..),
PStakeUsage (..),
PStakeRole (..),
-- * Utility functions
stakeLocked,
pgetStakeUsage,
pstakeLocked,
pnumCreatedProposals,
pextractVoteOption,
pgetStakeRole,
pisVoter,
pisCreator,
pisPureCreator,
pisIrrelevant,
) where
import Agora.Plutarch.Orphans ()
@ -43,14 +49,15 @@ import Plutarch.Extra.IsData (
DerivePConstantViaDataList (..),
ProductIsData (ProductIsData),
)
import Plutarch.Extra.List (pmapMaybe, pnotNull)
import Plutarch.Extra.List (pnotNull)
import Plutarch.Extra.Other (DerivePNewtype' (..))
import Plutarch.Extra.TermCont (pletFieldsC)
import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (..))
import Plutarch.SafeMoney (PDiscrete)
import Plutarch.Show (PShow (..))
import PlutusLedgerApi.V1 (PubKeyHash)
import PlutusLedgerApi.V1.Value (AssetClass)
import PlutusTx qualified
import Prelude ((+))
import Prelude hiding (Num (..))
--------------------------------------------------------------------------------
@ -69,8 +76,7 @@ data Stake = Stake
GHC.Generic
)
{- | A lock placed on a Stake datum in order to prevent
depositing and withdrawing when votes are in place.
{- | Locks that are stored in the stake datums for various purposes.
NOTE: Due to retracting votes always being possible,
this lock will only lock with contention on the proposal.
@ -97,30 +103,45 @@ data Stake = Stake
@since 0.1.0
-}
data ProposalLock = ProposalLock
{ vote :: ResultTag
-- ^ What was voted on. This allows retracting votes to
-- undo their vote.
, proposalId :: ProposalId
-- ^ Identifies the proposal. See 'ProposalId' for further
-- comments on its significance.
}
data ProposalLock
= -- | The stake was used to create a proposal.
--
-- This kind of lock is placed upon the creation of a proposal, in order
-- to limit creation of proposals per stake.
--
-- See also: https://github.com/Liqwid-Labs/agora/issues/68
--
-- @since 0.2.0
Created
ProposalId
-- ^ The identifier of the proposal.
| -- | The stake was used to vote on a proposal.
--
-- This kind of lock is placed while voting on a propsoal, in order to
-- prevent depositing and withdrawing when votes are in place.
--
-- @since 0.2.0
Voted
ProposalId
-- ^ The identifier of the proposal.
ResultTag
-- ^ The option which was voted on. This allows votes to be retracted.
deriving stock
( -- | @since 0.1.0
Show
, -- | @since 0.1.0
GHC.Generic
)
deriving anyclass (Generic)
deriving
deriving anyclass
( -- | @since 0.1.0
PlutusTx.ToData
, -- | @since 0.1.0
PlutusTx.FromData
, -- | @since 0.1.0
PlutusTx.UnsafeFromData
Generic
)
via (ProductIsData ProposalLock)
PlutusTx.makeIsDataIndexed
''ProposalLock
[ ('Created, 0)
, ('Voted, 1)
]
{- | Haskell-level redeemer for Stake scripts.
@ -138,12 +159,12 @@ data StakeRedeemer
-- This needs to be done in sync with casting a vote, otherwise
-- it's possible for a lock to be permanently placed on the stake,
-- and then the funds are lost.
PermitVote ProposalLock
PermitVote
| -- | Retract a vote, removing it from the 'lockedBy' field. See 'ProposalLock'.
-- This action checks for permission of the 'Agora.Proposal.Proposal'. Finished proposals are
-- always allowed to have votes retracted and won't affect the Proposal datum,
-- allowing 'Stake's to be unlocked.
RetractVotes [ProposalLock]
RetractVotes
| -- | The owner can consume stake if nothing is changed about it.
-- If the proposal token moves, this is equivalent to the owner consuming it.
WitnessStake
@ -165,7 +186,7 @@ PlutusTx.makeIsDataIndexed
data StakeDatum = StakeDatum
{ stakedAmount :: Tagged GTTag Integer
-- ^ Tracks the amount of governance token staked in the datum.
-- This also acts as the voting weight for 'Agora.Proposal.Proposal's.
-- This also acts as the voting weight for 'Agora.Proposal.Proposal's.
, owner :: PubKeyHash
-- ^ The hash of the public key this stake belongs to.
--
@ -173,7 +194,7 @@ data StakeDatum = StakeDatum
-- https://github.com/Liqwid-Labs/agora/issues/45
, lockedBy :: [ProposalLock]
-- ^ The current proposals locking this stake. This field must be empty
-- for the stake to be usable for deposits and withdrawals.
-- for the stake to be usable for deposits and withdrawals.
}
deriving stock (Show, GHC.Generic)
deriving anyclass (Generic)
@ -227,13 +248,20 @@ newtype PStakeDatum (s :: S) = PStakeDatum
via (DerivePNewtype' PStakeDatum)
-- | @since 0.1.0
instance Plutarch.Lift.PUnsafeLiftDecl PStakeDatum where type PLifted PStakeDatum = StakeDatum
instance Plutarch.Lift.PUnsafeLiftDecl PStakeDatum where
type PLifted PStakeDatum = StakeDatum
-- | @since 0.1.0
deriving via (DerivePConstantViaDataList StakeDatum PStakeDatum) instance (Plutarch.Lift.PConstantDecl StakeDatum)
deriving via
(DerivePConstantViaDataList StakeDatum PStakeDatum)
instance
(Plutarch.Lift.PConstantDecl StakeDatum)
-- | @since 0.1.0
deriving via PAsData (DerivePNewtype' PStakeDatum) instance PTryFrom PData (PAsData PStakeDatum)
deriving via
PAsData (DerivePNewtype' PStakeDatum)
instance
PTryFrom PData (PAsData PStakeDatum)
{- | Plutarch-level redeemer for Stake scripts.
@ -244,8 +272,8 @@ data PStakeRedeemer (s :: S)
PDepositWithdraw (Term s (PDataRecord '["delta" ':= PDiscrete GTTag]))
| -- | Destroy a stake, retrieving its LQ, the minimum ADA and any other assets.
PDestroy (Term s (PDataRecord '[]))
| PPermitVote (Term s (PDataRecord '["lock" ':= PProposalLock]))
| PRetractVotes (Term s (PDataRecord '["locks" ':= PBuiltinList (PAsData PProposalLock)]))
| PPermitVote (Term s (PDataRecord '[]))
| PRetractVotes (Term s (PDataRecord '[]))
| PWitnessStake (Term s (PDataRecord '[]))
deriving stock
( -- | @since 0.1.0
@ -267,65 +295,37 @@ data PStakeRedeemer (s :: S)
)
via PIsDataReprInstances PStakeRedeemer
-- | @since 0.1.0
deriving via
PAsData (PIsDataReprInstances PStakeRedeemer)
instance
PTryFrom PData (PAsData PStakeRedeemer)
instance Plutarch.Lift.PUnsafeLiftDecl PStakeRedeemer where type PLifted PStakeRedeemer = StakeRedeemer
deriving via (DerivePConstantViaData StakeRedeemer PStakeRedeemer) instance (Plutarch.Lift.PConstantDecl StakeRedeemer)
-- | @since 0.1.0
instance Plutarch.Lift.PUnsafeLiftDecl PStakeRedeemer where
type PLifted PStakeRedeemer = StakeRedeemer
-- | @since 0.1.0
deriving via
(DerivePConstantViaData StakeRedeemer PStakeRedeemer)
instance
(Plutarch.Lift.PConstantDecl StakeRedeemer)
{- | Plutarch-level version of 'ProposalLock'.
@since 0.1.0
@since 0.2.0
-}
newtype PProposalLock (s :: S) = PProposalLock
{ getProposalLock ::
Term
s
( PDataRecord
'[ "vote" ':= PResultTag
, "proposalTag" ':= PProposalId
]
)
}
deriving stock (GHC.Generic)
deriving anyclass (Generic)
deriving anyclass (PIsDataRepr)
deriving
(PlutusType, PIsData, PDataFields, PEq)
via (DerivePNewtype' PProposalLock)
deriving via
PAsData (DerivePNewtype' PProposalLock)
instance
PTryFrom PData (PAsData PProposalLock)
instance Plutarch.Lift.PUnsafeLiftDecl PProposalLock where type PLifted PProposalLock = ProposalLock
deriving via (DerivePConstantViaDataList ProposalLock PProposalLock) instance (Plutarch.Lift.PConstantDecl ProposalLock)
--------------------------------------------------------------------------------
{- | Check whether a Stake is locked. If it is locked, various actions are unavailable.
@since 0.1.0
-}
stakeLocked :: forall (s :: S). Term s (PStakeDatum :--> PBool)
stakeLocked = phoistAcyclic $
plam $ \stakeDatum ->
let locks :: Term _ (PBuiltinList (PAsData PProposalLock))
locks = pfield @"lockedBy" # stakeDatum
in pnotNull # locks
{- | Represent the usage of a stake on a particular proposal.
A stake can be used to either create or vote on a proposal.
@since 0.1.0
-}
data PStakeUsage (s :: S)
= PVotedFor (Term s PResultTag)
| PCreated
| PDidNothing
data PProposalLock (s :: S)
= PCreated (Term s (PDataRecord '["created" ':= PProposalId]))
| PVoted
( Term
s
( PDataRecord
'[ "votedOn" ':= PProposalId
, "votedFor" ':= PResultTag
]
)
)
deriving stock
( -- | @since 0.1.0
GHC.Generic
@ -334,51 +334,212 @@ data PStakeUsage (s :: S)
( -- | @since 0.1.0
Generic
, -- | @since 0.1.0
HasDatatypeInfo
)
deriving anyclass
( -- | @since 0.1.0
PIsDataRepr
)
deriving
( -- | @since 0.1.0
PlutusType
, -- | @since 0.1.0
HasDatatypeInfo
PIsData
, -- | @since 0.1.0
PEq
)
via (PIsDataReprInstances PProposalLock)
{- | / O(n) /.Return the usage of a stake on a particular proposal,
given the 'lockedBy' field of a stake and the target proposal.
-- | @since 0.1.0
deriving via
PAsData (PIsDataReprInstances PProposalLock)
instance
PTryFrom PData (PAsData PProposalLock)
@since 0.1.0
-- | @since 0.1.0
instance Plutarch.Lift.PUnsafeLiftDecl PProposalLock where
type PLifted PProposalLock = ProposalLock
-- | @since 0.1.0
deriving via
(DerivePConstantViaData ProposalLock PProposalLock)
instance
(Plutarch.Lift.PConstantDecl ProposalLock)
-- | @since 0.2.0
instance PShow PProposalLock where
pshow' :: Bool -> Term s PProposalLock -> Term s PString
pshow' True x = "(" <> pshow' False x <> ")"
pshow' False lock = pmatch lock $ \case
PCreated ((pfield @"created" #) -> pid) -> "PCreated " <> pshow' True pid
PVoted x -> pletFields @'["votedOn", "votedFor"] x $ \xF ->
"PVoted " <> pshow' True xF.votedOn <> " " <> pshow' True xF.votedFor
--------------------------------------------------------------------------------
{- | Check whether a Stake is locked. If it is locked, various actions are unavailable.
@since 0.2.0
-}
pgetStakeUsage ::
Term
_
( PBuiltinList (PAsData PProposalLock)
:--> PProposalId
:--> PStakeUsage
pstakeLocked :: forall (s :: S). Term s (PStakeDatum :--> PBool)
pstakeLocked = phoistAcyclic $
plam $ \stakeDatum ->
let locks :: Term _ (PBuiltinList (PAsData PProposalLock))
locks = pfield @"lockedBy" # stakeDatum
in pnotNull # locks
{- | Get the number of *alive* proposals that were created by the given stake.
@since 0.2.0
-}
pnumCreatedProposals :: Term s (PBuiltinList (PAsData PProposalLock) :--> PInteger)
pnumCreatedProposals =
phoistAcyclic $
plam $ \l ->
pfoldl
# phoistAcyclic
( plam
( \c (pfromData -> lock) ->
c
+ pmatch
lock
( \case
PCreated _ -> 1
_ -> 0
)
)
)
# 0
# l
{- | The role of a stake for a particular proposal. Scott-encoded.
@since 0.2.0
-}
data PStakeRole (s :: S)
= -- | The stake was used to vote on the proposal.
PVoter
(Term s PResultTag)
-- ^ The option which was voted for.
| -- | The stake was used to create the propsoal.
PCreator
| -- | The stake was used to both create and vote on the proposal.
PBoth
(Term s PResultTag)
-- ^ The option which was voted for.
| -- | The stake has nothing to do with the given propsoal.
PIrrelevant
deriving stock
( -- | @since 0.2.0
GHC.Generic
)
deriving anyclass
( -- | @since 0.2.0
Generic
, -- | @since 0.2.0
PlutusType
, -- | @since 0.2.0
HasDatatypeInfo
, -- | @since 0.2.0
PEq
)
pgetStakeUsage = phoistAcyclic $
plam $ \locks pid ->
let -- All locks from the given proposal.
filteredLocks =
pmapMaybe
# plam
( \lock'@(pfromData -> lock) -> unTermCont $ do
lockF <- pletFieldsC @'["proposalTag"] lock
pure $
{- | Retutn true if the stake was used to voted on the proposal.
@since 0.2.0
-}
pisVoter :: Term s (PStakeRole :--> PBool)
pisVoter = phoistAcyclic $
plam $ \sr -> pmatch sr $ \case
PVoter _ -> pconstant True
PBoth _ -> pconstant True
_ -> pconstant False
{- | Retutn true if the stake was used to create the proposal.
@since 0.2.0
-}
pisCreator :: Term s (PStakeRole :--> PBool)
pisCreator = phoistAcyclic $
plam $ \sr -> pmatch sr $ \case
PCreator -> pconstant True
PBoth _ -> pconstant True
_ -> pconstant False
{- | Retutn true if the stake was used to create the proposal, but not vote on
the proposal.
@since 0.2.0
-}
pisPureCreator :: Term s (PStakeRole :--> PBool)
pisPureCreator = phoistAcyclic $
plam $ \sr -> pmatch sr $ \case
PCreator -> pconstant True
_ -> pconstant False
{- | Return true if the stake isn't related to the proposal.
@since 0.2.0
-}
pisIrrelevant :: Term s (PStakeRole :--> PBool)
pisIrrelevant = phoistAcyclic $
plam $ \sr -> pmatch sr $ \case
PIrrelevant -> pconstant True
_ -> pconstant False
{- | Get the role of a stake for the proposal specified by the poroposal id,
given the 'StakeDatum.lockedBy' field of the stake.
Note that the list of locks is cosidered valid only if it contains at most
two locks from the given proposal: one voter lock and one creator lock.
@since 0.2.0
-}
pgetStakeRole :: Term s (PProposalId :--> PBuiltinList (PAsData PProposalLock) :--> PStakeRole)
pgetStakeRole = phoistAcyclic $
plam $ \pid locks ->
pfoldl
# plam
( \role (pfromData -> lock) ->
let thisRole = pmatch lock $ \case
PCreated ((pfield @"created" #) -> pid') ->
pif
(lockF.proposalTag #== pid)
(pcon $ PJust lock')
(pcon PNothing)
)
# locks
(pid' #== pid)
(pcon PCreator)
(pcon PIrrelevant)
PVoted lock' -> pletFields @'["votedOn", "votedFor"] lock' $ \lockF ->
pif
(lockF.votedOn #== pid)
(pcon $ PVoter lockF.votedFor)
(pcon PIrrelevant)
in pcombineStakeRole # thisRole # role
)
# pcon PIrrelevant
# locks
where
pcombineStakeRole :: Term s (PStakeRole :--> PStakeRole :--> PStakeRole)
pcombineStakeRole = phoistAcyclic $
plam $ \x y ->
let cannotCombine = ptraceError "duplicate roles"
in pmatch x $ \case
PVoter r -> pmatch y $ \case
PCreator -> pcon $ PBoth r
PIrrelevant -> x
_ -> cannotCombine
PCreator -> pmatch y $ \case
PVoter r -> pcon $ PBoth r
PIrrelevant -> x
_ -> cannotCombine
PBoth _ -> cannotCombine
PIrrelevant -> y
lockCount' = plength # filteredLocks
in plet lockCount' $ \lockCount ->
pif (lockCount #== 0) (pcon PDidNothing) $
pif
(lockCount #== 1)
( pcon $
PVotedFor $
pfromData $
pfield @"vote" #$ phead # filteredLocks
)
-- Note: see the implementation of the governor.
(pcon PCreated)
{- | Get the outcome that was voted for.
@since 0.2.0
-}
pextractVoteOption :: Term s (PStakeRole :--> PResultTag)
pextractVoteOption = phoistAcyclic $
plam $ \sr -> pmatch sr $ \case
PVoter r -> r
PBoth r -> r
_ -> ptraceError "not voter"

View file

@ -18,7 +18,7 @@ import Agora.Stake (
),
Stake (gtClassRef, proposalSTClass),
StakeRedeemer (WitnessStake),
stakeLocked,
pstakeLocked,
)
import Agora.Utils (
mustBePJust,
@ -109,7 +109,7 @@ stakePolicy gtClassRef =
pif
(psymbolValueOf # ownSymbol # txOutF.value #== 1)
( let datum = mustFindDatum' @PStakeDatum # txOutF.datumHash # txInfoF.datums
in pnot # (stakeLocked # datum)
in pnot # (pstakeLocked # datum)
)
(pconstant False)
)
@ -263,7 +263,7 @@ stakeValidator stake =
spentST <- pletC $ psymbolValueOf # stCurrencySymbol #$ valueSpent
-- Is the stake currently locked?
stakeIsLocked <- pletC $ stakeLocked # stakeDatum'
stakeIsLocked <- pletC $ pstakeLocked # stakeDatum'
pure $
pmatch stakeRedeemer $ \case
@ -287,7 +287,7 @@ stakeValidator stake =
proposalSTClass = passetClass # pconstant propCs # pconstant propTn
spentProposalST = passetClassValueOf # valueSpent # proposalSTClass
proposalTokenMoved <- pletC $ spentProposalST #== 1
proposalTokenMoved <- pletC $ 1 #<= spentProposalST
-- Filter out own outputs using own address and ST.
ownOutputs <-
@ -371,9 +371,20 @@ stakeValidator stake =
pletC $
pdata resolvedF.value #== pdata ownOutputValue
onlyLocksUpdated <-
pletC $
let templateStakeDatum =
mkRecordConstr
PStakeDatum
( #stakedAmount .= stakeDatum.stakedAmount
.& #owner .= stakeDatum.owner
.& #lockedBy .= pfield @"lockedBy" # stakeOut
)
in stakeOut #== templateStakeDatum
pure $
pmatch stakeRedeemer $ \case
PRetractVotes l -> unTermCont $ do
PRetractVotes _ -> unTermCont $ do
pguardC
"Owner signs this transaction"
ownerSignsTransaction
@ -383,18 +394,8 @@ stakeValidator stake =
pguardC "Proposal ST spent" proposalTokenMoved
pguardC "A UTXO must exist with the correct output" $
let expectedLocks = pfield @"locks" # l
expectedDatum =
mkRecordConstr
PStakeDatum
( #stakedAmount .= stakeDatum.stakedAmount
.& #owner .= stakeDatum.owner
.& #lockedBy .= expectedLocks
)
valueCorrect = ownOutputValueUnchanged
outputDatumCorrect = stakeOut #== expectedDatum
let valueCorrect = ownOutputValueUnchanged
outputDatumCorrect = onlyLocksUpdated
in foldl1
(#&&)
[ ptraceIfFalse "valueCorrect" valueCorrect
@ -405,34 +406,21 @@ stakeValidator stake =
------------------------------------------------------------
PPermitVote l -> unTermCont $ do
PPermitVote _ -> unTermCont $ do
pguardC
"Owner signs this transaction"
ownerSignsTransaction
let proposalTokenMinted =
passetClassValueOf # txInfoF.mint # proposalSTClass #== 1
-- This puts trust into the Proposal. The Proposal must necessarily check
-- that this is not abused.
pguardC "Proposal ST spent" proposalTokenMoved
-- Update the stake datum, but only the 'lockedBy' field.
let -- We actually don't know whether the given lock is valid or not.
-- This is checked in the proposal validator.
newLock = pfield @"lock" # l
-- Prepend the new lock to the existing locks.
expectedLocks = pcons # newLock # stakeDatum.lockedBy
expectedDatum <-
pletC $
mkRecordConstr
PStakeDatum
( #stakedAmount .= stakeDatum.stakedAmount
.& #owner .= stakeDatum.owner
.& #lockedBy .= pdata expectedLocks
)
pguardC "Proposal ST spent or minted" $
proposalTokenMoved #|| proposalTokenMinted
pguardC "A UTXO must exist with the correct output" $
let correctOutputDatum = stakeOut #== expectedDatum
let correctOutputDatum = onlyLocksUpdated
valueCorrect = ownOutputValueUnchanged
in foldl1
(#&&)

286
bench.csv
View file

@ -2,69 +2,233 @@ name,cpu,mem,size
Agora/Effects/Treasury Withdrawal Effect/effect/Simple,333327612,830203,3674
Agora/Effects/Treasury Withdrawal Effect/effect/Simple with multiple treasuries ,492387542,1197315,3986
Agora/Effects/Treasury Withdrawal Effect/effect/Mixed Assets,456007605,1104500,3859
Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/governor validator should pass,87839169,243032,8561
Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass,106082031,292993,3609
Agora/Stake/policy/stakeCreation,50939580,148729,2387
Agora/Stake/validator/stakeDepositWithdraw deposit,150745141,416137,4995
Agora/Stake/validator/stakeDepositWithdraw withdraw,150745141,416137,4983
Agora/Proposal/policy/proposalCreation,23140177,69194,1515
Agora/Proposal/validator/cosignature/legal/with 1 cosigners/propsoal,235408912,657765,8097
Agora/Proposal/validator/cosignature/legal/with 1 cosigners/stake,125665131,316762,5462
Agora/Proposal/validator/cosignature/legal/with 5 cosigners/propsoal,680441047,1897008,10727
Agora/Proposal/validator/cosignature/legal/with 5 cosigners/stake,576106975,1490610,7972
Agora/Proposal/validator/cosignature/legal/with 10 cosigners/propsoal,1351073436,3706315,14015
Agora/Proposal/validator/cosignature/legal/with 10 cosigners/stake,1148637636,2982695,11109
Agora/Proposal/validator/cosignature/illegal/duplicate cosigners/stake,125665131,316762,5462
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: VotingReady/stake,125665131,316762,5462
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Locked/stake,125665131,316762,5462
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Finished/stake,125665131,316762,5462
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: VotingReady/stake,576106975,1490610,7972
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Locked/stake,576106975,1490610,7972
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Finished/stake,576106975,1490610,7972
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: VotingReady/stake,1148637636,2982695,11109
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Locked/stake,1148637636,2982695,11109
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Finished/stake,1148637636,2982695,11109
Agora/Proposal/validator/voting/legal/propsoal,246896882,688919,8069
Agora/Proposal/validator/voting/legal/stake,141234659,368136,5481
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/propsoal,222376736,631090,8052
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/stake,125665131,316762,5459
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/propsoal,217322044,620369,8054
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/stake,125665131,316762,5461
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/illegal/insufficient cosigns/stake,118020743,304972,5389
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/propsoal,614587307,1766683,10875
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/stake,548619697,1410656,8162
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/propsoal,239691392,682433,8415
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/stake,125665131,316762,5702
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/illegal/insufficient cosigns/stake,446252055,1166812,7811
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/propsoal,1196289192,3454898,14404
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/stake,1201388310,3136405,11540
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/propsoal,267653077,760013,8868
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/stake,125665131,316762,6004
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/illegal/insufficient cosigns/stake,1025012867,2732083,10837
Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/propsoal,250229153,709227,8061
Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/stake,125665131,316762,5466
Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/propsoal,238990044,676396,8061
Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/stake,125665131,316762,5466
Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/propsoal,236162599,670386,8055
Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/stake,125665131,316762,5462
Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/propsoal,237293577,672790,8055
Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/stake,125665131,316762,5462
Agora/Proposal/validator/advancing/illegal/insufficient votes/stake,125665131,316762,5462
Agora/Proposal/validator/advancing/illegal/initial state is Finished/stake,125665131,316762,5454
"Agora/Proposal/validator/unlocking/legal/1 proposals, voter, unlock stake + retract votes, VotingReady",245855872,689807,8029
"Agora/Proposal/validator/unlocking/legal/1 proposals, creator, unlock stake, Finished",215131610,613807,8031
"Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/1 proposals, voter, unlock stake, Finished",212428891,605718,8033
"Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/1 proposals, voter, unlock stake, Locked",212428891,605718,8033
"Agora/Proposal/validator/unlocking/legal/42 proposals, voter, unlock stake + retract votes, VotingReady",1775520444,5200586,29137
"Agora/Proposal/validator/unlocking/legal/42 proposals, creator, unlock stake, Finished",1448162043,4319059,29321
"Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/42 proposals, voter, unlock stake, Finished",1340521669,3979526,29305
"Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/42 proposals, voter, unlock stake, Locked",1340521669,3979526,29305
Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/governor validator should pass,88940927,246756,8891
Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass,107090537,296185,3627
Agora/Stake/policy/stakeCreation,51008580,149029,2522
Agora/Stake/validator/stakeDepositWithdraw deposit,183506412,498838,4745
Agora/Stake/validator/stakeDepositWithdraw withdraw,183506412,498838,4733
Agora/Proposal/policy (proposal creation)/legal/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/legal/governor,327971301,871386,9370
Agora/Proposal/policy (proposal creation)/legal/stake,152415805,398403,5404
Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/stake,152415805,398403,5404
Agora/Proposal/policy (proposal creation)/illegal/use other's stake/proposal,34975627,103548,2086
Agora/Proposal/policy (proposal creation)/illegal/altered stake/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/proposal,34975627,103548,2125
Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/stake,157849465,413053,5412
Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/proposal,34975627,103548,2137
Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/stake,158878297,416511,5434
Agora/Proposal/policy (proposal creation)/illegal/loose time range/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/illegal/loose time range/stake,152415805,398403,5404
Agora/Proposal/policy (proposal creation)/illegal/open time range/proposal,34975627,103548,2113
Agora/Proposal/policy (proposal creation)/illegal/open time range/stake,152415805,398403,5400
Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/stake,152415805,398403,5404
Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/stake,152415805,398403,5404
Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/proposal,34975627,103548,2117
Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/stake,152415805,398403,5404
Agora/Proposal/validator/cosignature/legal/with 1 cosigners/propsoal,232230876,649441,8097
Agora/Proposal/validator/cosignature/legal/with 1 cosigners/stake,122255811,317464,5213
Agora/Proposal/validator/cosignature/legal/with 5 cosigners/propsoal,662894867,1848188,10727
Agora/Proposal/validator/cosignature/legal/with 5 cosigners/stake,553050999,1459872,7723
Agora/Proposal/validator/cosignature/legal/with 10 cosigners/propsoal,1315567076,3606875,14015
Agora/Proposal/validator/cosignature/legal/with 10 cosigners/stake,1101023340,2912657,10860
Agora/Proposal/validator/cosignature/illegal/duplicate cosigners/stake,122255811,317464,5213
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: VotingReady/stake,122255811,317464,5213
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Locked/stake,122255811,317464,5213
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Finished/stake,122255811,317464,5213
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: VotingReady/stake,553050999,1459872,7723
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Locked/stake,553050999,1459872,7723
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Finished/stake,553050999,1459872,7723
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: VotingReady/stake,1101023340,2912657,10860
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Locked/stake,1101023340,2912657,10860
Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Finished/stake,1101023340,2912657,10860
Agora/Proposal/validator/voting/legal/propsoal,253541830,711367,8079
Agora/Proposal/validator/voting/legal/stake,139493011,366217,5239
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/propsoal,222392288,630302,8060
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/stake,122255811,317464,5222
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/propsoal,217337596,619581,8062
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/stake,122255811,317464,5224
Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/illegal/insufficient cosigns/stake,117978393,308804,5152
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/propsoal,602596705,1722841,10915
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/stake,499559031,1304096,7957
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/propsoal,239706944,681645,8423
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/stake,122255811,317464,5465
Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/illegal/insufficient cosigns/stake,446950999,1172710,7606
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/propsoal,1183788938,3402248,14484
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/stake,1129251912,2994677,11375
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/propsoal,267668629,759225,8876
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/stake,122255811,317464,5767
Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/illegal/insufficient cosigns/stake,1013080113,2701103,10673
Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/propsoal,253438293,715975,8069
Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/stake,122255811,317464,5229
Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/propsoal,242199184,683144,8069
Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/stake,122255811,317464,5229
Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/propsoal,239371739,677134,8063
Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/stake,122255811,317464,5225
Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/propsoal,240502717,679538,8063
Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/stake,122255811,317464,5225
Agora/Proposal/validator/advancing/illegal/insufficient votes/stake,122255811,317464,5225
Agora/Proposal/validator/advancing/illegal/initial state is Finished/stake,122255811,317464,5217
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/stake,128424052,334368,5219
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/propsoal,236436652,664524,8060
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/stake,131655298,343422,5235
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/propsoal,249908859,704466,8071
Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/stake,128424052,334368,5217
Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/propsoal,204228787,584379,8057
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/stake,128424052,334368,5233
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/propsoal,212663044,609283,8069
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/stake,128424052,334368,5223
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/propsoal,205544939,588263,8064
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/stake,128424052,334368,5223
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/propsoal,205544939,588263,8064
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/stake,131655298,343422,5239
Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/propsoal,219548722,629597,8075
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/stake,279213296,711004,7303
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/propsoal,379077900,1077188,10120
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/stake,295369526,756274,7380
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/propsoal,444606435,1268442,10172
Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/stake,279213296,711004,7293
Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/propsoal,312309599,902235,10113
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/stake,279213296,711004,7374
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/propsoal,350698580,1013987,10166
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/stake,279213296,711004,7324
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/propsoal,317778859,917311,10141
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/stake,279213296,711004,7324
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/propsoal,317778859,917311,10141
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/stake,295369526,756274,7400
Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/propsoal,383838970,1109957,10192
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/stake,467699851,1181799,9909
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/propsoal,557379460,1593018,12696
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/stake,500012311,1272339,10060
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/propsoal,687978405,1973412,12797
Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/stake,467699851,1181799,9888
Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/propsoal,447410614,1299555,12683
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/stake,467699851,1181799,10049
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/propsoal,523243000,1519867,12786
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/stake,467699851,1181799,9949
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/propsoal,458071259,1328621,12736
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/stake,467699851,1181799,9949
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/propsoal,458071259,1328621,12736
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/stake,500012311,1272339,10100
Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/propsoal,589201780,1710407,12837
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/stake,1674013803,4194887,26674
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/propsoal,1698509444,4894330,29250
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/stake,1809726135,4575155,27362
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/propsoal,2245559013,6485220,29709
Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/stake,1674013803,4194887,26590
Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/propsoal,1312057110,3842403,29206
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/stake,1674013803,4194887,27301
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/propsoal,1627527288,4757499,29648
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/stake,1674013803,4194887,26843
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/propsoal,1355942619,3961005,29419
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/stake,1674013803,4194887,26843
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/propsoal,1355942619,3961005,29419
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/stake,1809726135,4575155,27531
Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/propsoal,1903523764,5553287,29878
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter, status: Draft/stake",128424052,334368,5219
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter, status: Locked/stake",128424052,334368,5219
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter, status: Finished/stake",128424052,334368,5219
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator, status: Draft/stake",124053466,322518,5221
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator, status: Locked/stake",124053466,322518,5221
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator, status: Finished/stake",124053466,322518,5221
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both, status: Draft/stake",131655298,343422,5235
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both, status: Locked/stake",131655298,343422,5235
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both, status: Finished/stake",131655298,343422,5235
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake",120822220,313464,5201
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake",120822220,313464,5201
"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake",120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake,120822220,313464,5201
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Draft/stake,128424052,334368,5217
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: VotingReady/stake,128424052,334368,5217
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Locked/stake,128424052,334368,5217
Agora/Proposal/validator/unlocking/illegal/with 1 proposals/creator: retract votes/stake,128424052,334368,5215
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter, status: Draft/stake",279213296,711004,7303
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter, status: Locked/stake",279213296,711004,7303
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter, status: Finished/stake",279213296,711004,7303
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator, status: Draft/stake",272564030,693562,7309
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator, status: Locked/stake",272564030,693562,7309
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator, status: Finished/stake",272564030,693562,7309
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both, status: Draft/stake",295369526,756274,7380
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both, status: Locked/stake",295369526,756274,7380
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both, status: Finished/stake",295369526,756274,7380
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake",256407800,648292,7221
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake",256407800,648292,7221
"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake",256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake,256407800,648292,7221
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Draft/stake,279213296,711004,7293
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: VotingReady/stake,279213296,711004,7293
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Locked/stake,279213296,711004,7293
Agora/Proposal/validator/unlocking/illegal/with 5 proposals/creator: retract votes/stake,279213296,711004,7283
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter, status: Draft/stake",467699851,1181799,9909
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter, status: Locked/stake",467699851,1181799,9909
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter, status: Finished/stake",467699851,1181799,9909
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator, status: Draft/stake",458202235,1157367,9920
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator, status: Locked/stake",458202235,1157367,9920
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator, status: Finished/stake",458202235,1157367,9920
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both, status: Draft/stake",500012311,1272339,10060
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both, status: Locked/stake",500012311,1272339,10060
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both, status: Finished/stake",500012311,1272339,10060
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake",425889775,1066827,9746
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake",425889775,1066827,9746
"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake",425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake,425889775,1066827,9746
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Draft/stake,467699851,1181799,9888
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: VotingReady/stake,467699851,1181799,9888
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Locked/stake,467699851,1181799,9888
Agora/Proposal/validator/unlocking/illegal/with 10 proposals/creator: retract votes/stake,467699851,1181799,9868
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter, status: Draft/stake",1674013803,4194887,26674
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter, status: Locked/stake",1674013803,4194887,26674
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter, status: Finished/stake",1674013803,4194887,26674
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator, status: Draft/stake",1646286747,4125719,26736
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator, status: Locked/stake",1646286747,4125719,26736
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator, status: Finished/stake",1646286747,4125719,26736
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both, status: Draft/stake",1809726135,4575155,27362
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both, status: Locked/stake",1809726135,4575155,27362
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both, status: Finished/stake",1809726135,4575155,27362
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake",1510574415,3745451,25961
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake",1510574415,3745451,25961
"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake",1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake,1510574415,3745451,25961
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Draft/stake,1674013803,4194887,26590
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: VotingReady/stake,1674013803,4194887,26590
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Locked/stake,1674013803,4194887,26590
Agora/Proposal/validator/unlocking/illegal/with 42 proposals/creator: retract votes/stake,1674013803,4194887,26506
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,21017788,55883,806
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,33204186,88241,900
Agora/Treasury/Validator/Positive/Allows for effect changes,31556709,81546,1452
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,21017788,55883,806
Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,33204186,88241,900
Agora/Governor/policy/GST minting,51007235,144191,2034
Agora/Governor/validator/proposal creation,309689999,834675,9064
Agora/Governor/validator/GATs minting,418560845,1137908,9187
Agora/Governor/validator/mutate governor state,88986020,248491,8662
Agora/Governor/policy/GST minting,51480023,145787,2048
Agora/Governor/validator/proposal creation,303114849,813451,9390
Agora/Governor/validator/GATs minting,422654153,1147158,9516
Agora/Governor/validator/mutate governor state,90087778,252215,8991

1 name cpu mem size
2 Agora/Effects/Treasury Withdrawal Effect/effect/Simple 333327612 830203 3674
3 Agora/Effects/Treasury Withdrawal Effect/effect/Simple with multiple treasuries 492387542 1197315 3986
4 Agora/Effects/Treasury Withdrawal Effect/effect/Mixed Assets 456007605 1104500 3859
5 Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/governor validator should pass 87839169 88940927 243032 246756 8561 8891
6 Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass 106082031 107090537 292993 296185 3609 3627
7 Agora/Stake/policy/stakeCreation 50939580 51008580 148729 149029 2387 2522
8 Agora/Stake/validator/stakeDepositWithdraw deposit 150745141 183506412 416137 498838 4995 4745
9 Agora/Stake/validator/stakeDepositWithdraw withdraw 150745141 183506412 416137 498838 4983 4733
10 Agora/Proposal/policy/proposalCreation Agora/Proposal/policy (proposal creation)/legal/proposal 23140177 34975627 69194 103548 1515 2117
11 Agora/Proposal/validator/cosignature/legal/with 1 cosigners/propsoal Agora/Proposal/policy (proposal creation)/legal/governor 235408912 327971301 657765 871386 8097 9370
12 Agora/Proposal/validator/cosignature/legal/with 1 cosigners/stake Agora/Proposal/policy (proposal creation)/legal/stake 125665131 152415805 316762 398403 5462 5404
13 Agora/Proposal/validator/cosignature/legal/with 5 cosigners/propsoal Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/proposal 680441047 34975627 1897008 103548 10727 2117
14 Agora/Proposal/validator/cosignature/legal/with 5 cosigners/stake Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/stake 576106975 152415805 1490610 398403 7972 5404
15 Agora/Proposal/validator/cosignature/legal/with 10 cosigners/propsoal Agora/Proposal/policy (proposal creation)/illegal/use other's stake/proposal 1351073436 34975627 3706315 103548 14015 2086
16 Agora/Proposal/validator/cosignature/legal/with 10 cosigners/stake Agora/Proposal/policy (proposal creation)/illegal/altered stake/proposal 1148637636 34975627 2982695 103548 11109 2117
17 Agora/Proposal/validator/cosignature/illegal/duplicate cosigners/stake Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/proposal 125665131 34975627 316762 103548 5462 2125
18 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: VotingReady/stake Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/stake 125665131 157849465 316762 413053 5462 5412
19 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Locked/stake Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/proposal 125665131 34975627 316762 103548 5462 2137
20 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Finished/stake Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/stake 125665131 158878297 316762 416511 5462 5434
21 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: VotingReady/stake Agora/Proposal/policy (proposal creation)/illegal/loose time range/proposal 576106975 34975627 1490610 103548 7972 2117
22 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Locked/stake Agora/Proposal/policy (proposal creation)/illegal/loose time range/stake 576106975 152415805 1490610 398403 7972 5404
23 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Finished/stake Agora/Proposal/policy (proposal creation)/illegal/open time range/proposal 576106975 34975627 1490610 103548 7972 2113
24 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: VotingReady/stake Agora/Proposal/policy (proposal creation)/illegal/open time range/stake 1148637636 152415805 2982695 398403 11109 5400
25 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Locked/stake Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/proposal 1148637636 34975627 2982695 103548 11109 2117
26 Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Finished/stake Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/stake 1148637636 152415805 2982695 398403 11109 5404
27 Agora/Proposal/validator/voting/legal/propsoal Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/proposal 246896882 34975627 688919 103548 8069 2117
28 Agora/Proposal/validator/voting/legal/stake Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/stake 141234659 152415805 368136 398403 5481 5404
29 Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/propsoal Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/proposal 222376736 34975627 631090 103548 8052 2117
30 Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/stake Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/stake 125665131 152415805 316762 398403 5459 5404
31 Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/propsoal Agora/Proposal/validator/cosignature/legal/with 1 cosigners/propsoal 217322044 232230876 620369 649441 8054 8097
32 Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/stake Agora/Proposal/validator/cosignature/legal/with 1 cosigners/stake 125665131 122255811 316762 317464 5461 5213
33 Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/illegal/insufficient cosigns/stake Agora/Proposal/validator/cosignature/legal/with 5 cosigners/propsoal 118020743 662894867 304972 1848188 5389 10727
34 Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/propsoal Agora/Proposal/validator/cosignature/legal/with 5 cosigners/stake 614587307 553050999 1766683 1459872 10875 7723
35 Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/stake Agora/Proposal/validator/cosignature/legal/with 10 cosigners/propsoal 548619697 1315567076 1410656 3606875 8162 14015
36 Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/propsoal Agora/Proposal/validator/cosignature/legal/with 10 cosigners/stake 239691392 1101023340 682433 2912657 8415 10860
37 Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/stake Agora/Proposal/validator/cosignature/illegal/duplicate cosigners/stake 125665131 122255811 316762 317464 5702 5213
38 Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/illegal/insufficient cosigns/stake Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: VotingReady/stake 446252055 122255811 1166812 317464 7811 5213
39 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/propsoal Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Locked/stake 1196289192 122255811 3454898 317464 14404 5213
40 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/stake Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Finished/stake 1201388310 122255811 3136405 317464 11540 5213
41 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/propsoal Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: VotingReady/stake 267653077 553050999 760013 1459872 8868 7723
42 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/stake Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Locked/stake 125665131 553050999 316762 1459872 6004 7723
43 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/illegal/insufficient cosigns/stake Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Finished/stake 1025012867 553050999 2732083 1459872 10837 7723
44 Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/propsoal Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: VotingReady/stake 250229153 1101023340 709227 2912657 8061 10860
45 Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/stake Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Locked/stake 125665131 1101023340 316762 2912657 5466 10860
46 Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/propsoal Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Finished/stake 238990044 1101023340 676396 2912657 8061 10860
47 Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/stake Agora/Proposal/validator/voting/legal/propsoal 125665131 253541830 316762 711367 5466 8079
48 Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/propsoal Agora/Proposal/validator/voting/legal/stake 236162599 139493011 670386 366217 8055 5239
49 Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/stake Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/propsoal 125665131 222392288 316762 630302 5462 8060
50 Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/propsoal Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to next state/stake 237293577 122255811 672790 317464 8055 5222
51 Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/stake Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/propsoal 125665131 217337596 316762 619581 5462 8062
52 Agora/Proposal/validator/advancing/illegal/insufficient votes/stake Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/legal/to failed state/stake 125665131 122255811 316762 317464 5462 5224
53 Agora/Proposal/validator/advancing/illegal/initial state is Finished/stake Agora/Proposal/validator/advancing/from draft/with 1 cosigner(s)/illegal/insufficient cosigns/stake 125665131 117978393 316762 308804 5454 5152
54 Agora/Proposal/validator/unlocking/legal/1 proposals, voter, unlock stake + retract votes, VotingReady Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/propsoal 245855872 602596705 689807 1722841 8029 10915
55 Agora/Proposal/validator/unlocking/legal/1 proposals, creator, unlock stake, Finished Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to next state/stake 215131610 499559031 613807 1304096 8031 7957
56 Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/1 proposals, voter, unlock stake, Finished Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/propsoal 212428891 239706944 605718 681645 8033 8423
57 Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/1 proposals, voter, unlock stake, Locked Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/legal/to failed state/stake 212428891 122255811 605718 317464 8033 5465
58 Agora/Proposal/validator/unlocking/legal/42 proposals, voter, unlock stake + retract votes, VotingReady Agora/Proposal/validator/advancing/from draft/with 5 cosigner(s)/illegal/insufficient cosigns/stake 1775520444 446950999 5200586 1172710 29137 7606
59 Agora/Proposal/validator/unlocking/legal/42 proposals, creator, unlock stake, Finished Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/propsoal 1448162043 1183788938 4319059 3402248 29321 14484
60 Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/42 proposals, voter, unlock stake, Finished Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to next state/stake 1340521669 1129251912 3979526 2994677 29305 11375
61 Agora/Proposal/validator/unlocking/legal/voter unlocks stake after voting/42 proposals, voter, unlock stake, Locked Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/propsoal 1340521669 267668629 3979526 759225 29305 8876
62 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/legal/to failed state/stake 122255811 317464 5767
63 Agora/Proposal/validator/advancing/from draft/with 10 cosigner(s)/illegal/insufficient cosigns/stake 1013080113 2701103 10673
64 Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/propsoal 253438293 715975 8069
65 Agora/Proposal/validator/advancing/legal/advance to next state/from: VotingReady/stake 122255811 317464 5229
66 Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/propsoal 242199184 683144 8069
67 Agora/Proposal/validator/advancing/legal/advance to next state/from: Locked/stake 122255811 317464 5229
68 Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/propsoal 239371739 677134 8063
69 Agora/Proposal/validator/advancing/legal/advance to failed state/from: VotingReady/stake 122255811 317464 5225
70 Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/propsoal 240502717 679538 8063
71 Agora/Proposal/validator/advancing/legal/advance to failed state/from: Locked/stake 122255811 317464 5225
72 Agora/Proposal/validator/advancing/illegal/insufficient votes/stake 122255811 317464 5225
73 Agora/Proposal/validator/advancing/illegal/initial state is Finished/stake 122255811 317464 5217
74 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/stake 128424052 334368 5219
75 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/propsoal 236436652 664524 8060
76 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/stake 131655298 343422 5235
77 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/propsoal 249908859 704466 8071
78 Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/stake 128424052 334368 5217
79 Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/propsoal 204228787 584379 8057
80 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/stake 128424052 334368 5233
81 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/propsoal 212663044 609283 8069
82 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/stake 128424052 334368 5223
83 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/propsoal 205544939 588263 8064
84 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/stake 128424052 334368 5223
85 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/propsoal 205544939 588263 8064
86 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/stake 131655298 343422 5239
87 Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/propsoal 219548722 629597 8075
88 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/stake 279213296 711004 7303
89 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/propsoal 379077900 1077188 10120
90 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/stake 295369526 756274 7380
91 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/propsoal 444606435 1268442 10172
92 Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/stake 279213296 711004 7293
93 Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/propsoal 312309599 902235 10113
94 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/stake 279213296 711004 7374
95 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/propsoal 350698580 1013987 10166
96 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/stake 279213296 711004 7324
97 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/propsoal 317778859 917311 10141
98 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/stake 279213296 711004 7324
99 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/propsoal 317778859 917311 10141
100 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/stake 295369526 756274 7400
101 Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/propsoal 383838970 1109957 10192
102 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/stake 467699851 1181799 9909
103 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/propsoal 557379460 1593018 12696
104 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/stake 500012311 1272339 10060
105 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/propsoal 687978405 1973412 12797
106 Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/stake 467699851 1181799 9888
107 Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/propsoal 447410614 1299555 12683
108 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/stake 467699851 1181799 10049
109 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/propsoal 523243000 1519867 12786
110 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/stake 467699851 1181799 9949
111 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/propsoal 458071259 1328621 12736
112 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/stake 467699851 1181799 9949
113 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/propsoal 458071259 1328621 12736
114 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/stake 500012311 1272339 10100
115 Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/propsoal 589201780 1710407 12837
116 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/stake 1674013803 4194887 26674
117 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/propsoal 1698509444 4894330 29250
118 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/stake 1809726135 4575155 27362
119 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/propsoal 2245559013 6485220 29709
120 Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/stake 1674013803 4194887 26590
121 Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/propsoal 1312057110 3842403 29206
122 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/stake 1674013803 4194887 27301
123 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/propsoal 1627527288 4757499 29648
124 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/stake 1674013803 4194887 26843
125 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/propsoal 1355942619 3961005 29419
126 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/stake 1674013803 4194887 26843
127 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/propsoal 1355942619 3961005 29419
128 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/stake 1809726135 4575155 27531
129 Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/propsoal 1903523764 5553287 29878
130 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter, status: Draft/stake 128424052 334368 5219
131 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter, status: Locked/stake 128424052 334368 5219
132 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter, status: Finished/stake 128424052 334368 5219
133 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator, status: Draft/stake 124053466 322518 5221
134 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator, status: Locked/stake 124053466 322518 5221
135 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator, status: Finished/stake 124053466 322518 5221
136 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both, status: Draft/stake 131655298 343422 5235
137 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both, status: Locked/stake 131655298 343422 5235
138 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both, status: Finished/stake 131655298 343422 5235
139 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake 120822220 313464 5201
140 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake 120822220 313464 5201
141 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake 120822220 313464 5201
142 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake 120822220 313464 5201
143 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake 120822220 313464 5201
144 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake 120822220 313464 5201
145 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake 120822220 313464 5201
146 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake 120822220 313464 5201
147 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake 120822220 313464 5201
148 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake 120822220 313464 5201
149 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake 120822220 313464 5201
150 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Draft/stake 128424052 334368 5217
151 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: VotingReady/stake 128424052 334368 5217
152 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Locked/stake 128424052 334368 5217
153 Agora/Proposal/validator/unlocking/illegal/with 1 proposals/creator: retract votes/stake 128424052 334368 5215
154 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter, status: Draft/stake 279213296 711004 7303
155 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter, status: Locked/stake 279213296 711004 7303
156 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter, status: Finished/stake 279213296 711004 7303
157 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator, status: Draft/stake 272564030 693562 7309
158 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator, status: Locked/stake 272564030 693562 7309
159 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator, status: Finished/stake 272564030 693562 7309
160 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both, status: Draft/stake 295369526 756274 7380
161 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both, status: Locked/stake 295369526 756274 7380
162 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both, status: Finished/stake 295369526 756274 7380
163 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake 256407800 648292 7221
164 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake 256407800 648292 7221
165 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake 256407800 648292 7221
166 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake 256407800 648292 7221
167 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake 256407800 648292 7221
168 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake 256407800 648292 7221
169 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake 256407800 648292 7221
170 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake 256407800 648292 7221
171 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake 256407800 648292 7221
172 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake 256407800 648292 7221
173 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake 256407800 648292 7221
174 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Draft/stake 279213296 711004 7293
175 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: VotingReady/stake 279213296 711004 7293
176 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Locked/stake 279213296 711004 7293
177 Agora/Proposal/validator/unlocking/illegal/with 5 proposals/creator: retract votes/stake 279213296 711004 7283
178 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter, status: Draft/stake 467699851 1181799 9909
179 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter, status: Locked/stake 467699851 1181799 9909
180 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter, status: Finished/stake 467699851 1181799 9909
181 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator, status: Draft/stake 458202235 1157367 9920
182 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator, status: Locked/stake 458202235 1157367 9920
183 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator, status: Finished/stake 458202235 1157367 9920
184 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both, status: Draft/stake 500012311 1272339 10060
185 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both, status: Locked/stake 500012311 1272339 10060
186 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both, status: Finished/stake 500012311 1272339 10060
187 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake 425889775 1066827 9746
188 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake 425889775 1066827 9746
189 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake 425889775 1066827 9746
190 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake 425889775 1066827 9746
191 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake 425889775 1066827 9746
192 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake 425889775 1066827 9746
193 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake 425889775 1066827 9746
194 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake 425889775 1066827 9746
195 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake 425889775 1066827 9746
196 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake 425889775 1066827 9746
197 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake 425889775 1066827 9746
198 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Draft/stake 467699851 1181799 9888
199 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: VotingReady/stake 467699851 1181799 9888
200 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Locked/stake 467699851 1181799 9888
201 Agora/Proposal/validator/unlocking/illegal/with 10 proposals/creator: retract votes/stake 467699851 1181799 9868
202 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter, status: Draft/stake 1674013803 4194887 26674
203 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter, status: Locked/stake 1674013803 4194887 26674
204 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter, status: Finished/stake 1674013803 4194887 26674
205 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator, status: Draft/stake 1646286747 4125719 26736
206 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator, status: Locked/stake 1646286747 4125719 26736
207 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator, status: Finished/stake 1646286747 4125719 26736
208 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both, status: Draft/stake 1809726135 4575155 27362
209 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both, status: Locked/stake 1809726135 4575155 27362
210 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both, status: Finished/stake 1809726135 4575155 27362
211 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant, status: Draft/stake 1510574415 3745451 25961
212 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant, status: Locked/stake 1510574415 3745451 25961
213 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant, status: Finished/stake 1510574415 3745451 25961
214 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draftretract votes: True/stake 1510574415 3745451 25961
215 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draftretract votes: False/stake 1510574415 3745451 25961
216 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: True/stake 1510574415 3745451 25961
217 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReadyretract votes: False/stake 1510574415 3745451 25961
218 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Lockedretract votes: True/stake 1510574415 3745451 25961
219 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Lockedretract votes: False/stake 1510574415 3745451 25961
220 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finishedretract votes: True/stake 1510574415 3745451 25961
221 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finishedretract votes: False/stake 1510574415 3745451 25961
222 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Draft/stake 1674013803 4194887 26590
223 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: VotingReady/stake 1674013803 4194887 26590
224 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Locked/stake 1674013803 4194887 26590
225 Agora/Proposal/validator/unlocking/illegal/with 42 proposals/creator: retract votes/stake 1674013803 4194887 26506
226 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple 21017788 55883 806
227 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs 33204186 88241 900
228 Agora/Treasury/Validator/Positive/Allows for effect changes 31556709 81546 1452
229 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple 21017788 55883 806
230 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs 33204186 88241 900
231 Agora/Governor/policy/GST minting 51007235 51480023 144191 145787 2034 2048
232 Agora/Governor/validator/proposal creation 309689999 303114849 834675 813451 9064 9390
233 Agora/Governor/validator/GATs minting 418560845 422654153 1137908 1147158 9187 9516
234 Agora/Governor/validator/mutate governor state 88986020 90087778 248491 252215 8662 8991