diff --git a/CHANGELOG.md b/CHANGELOG.md index a26e5e7..2b5e3c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ This format is based on [Keep A Changelog](https://keepachangelog.com/en/1.0.0). ### Modified +- Fixed bug that checks the proposal thresholds in an incorrect way. Added negative tests for the governor scripts. + + Included by [#146](https://github.com/Liqwid-Labs/agora/pull/146). + - Draft phase and cosigning for Proposals. Included by [#136](https://github.com/Liqwid-Labs/agora/pull/136). diff --git a/agora-specs/Property/Governor.hs b/agora-specs/Property/Governor.hs index 7d45d99..5bd5097 100644 --- a/agora-specs/Property/Governor.hs +++ b/agora-specs/Property/Governor.hs @@ -7,7 +7,7 @@ Property model and tests for 'Governor' related functions -} module Property.Governor (props) where -import Agora.Governor (GovernorDatum (..), governorDatumValid) +import Agora.Governor (GovernorDatum (..), pisGovernorDatumValid) import Agora.Governor.Scripts (governorPolicy) import Agora.Proposal ( ProposalId (ProposalId), @@ -30,6 +30,7 @@ import Plutarch.Context ( output, script, withDatum, + withMinting, withOutRef, withValue, ) @@ -43,6 +44,7 @@ import PlutusLedgerApi.V1.Value (assetClassValue) import Property.Generator (genInput, genOutput) import Sample.Shared ( govAssetClass, + govSymbol, govValidatorHash, governor, gstUTXORef, @@ -62,8 +64,6 @@ data GovernorDatumCases = ExecuteLE0 | CreateLE0 | VoteLE0 - | CreateLEVote - | ExecuteLVote | Correct deriving stock (Eq, Show) @@ -72,8 +72,6 @@ instance Universe GovernorDatumCases where [ ExecuteLE0 , CreateLE0 , VoteLE0 - , CreateLEVote - , ExecuteLVote , Correct ] @@ -87,15 +85,13 @@ instance Finite GovernorDatumCases where -} governorDatumValidProperty :: Property governorDatumValidProperty = - classifiedPropertyNative gen (const []) expected classifier governorDatumValid + classifiedPropertyNative gen (const []) expected classifier pisGovernorDatumValid where classifier :: GovernorDatum -> GovernorDatumCases classifier (proposalThresholds -> ProposalThresholds e c v) | e < 0 = ExecuteLE0 | c < 0 = CreateLE0 | v < 0 = VoteLE0 - | c > v = CreateLEVote - | v >= e = ExecuteLVote | otherwise = Correct expected :: GovernorDatum -> Maybe Bool @@ -106,7 +102,7 @@ governorDatumValidProperty = thres <- genProposalThresholds c let timing = ProposalTimingConfig 0 0 0 0 - return $ GovernorDatum thres (ProposalId 0) timing (MaxTimeRangeWidth 0) 3 + return $ GovernorDatum thres (ProposalId 0) timing (MaxTimeRangeWidth 1) 3 where taggedInteger p = Tagged <$> chooseInteger p genProposalThresholds :: GovernorDatumCases -> Gen ProposalThresholds @@ -127,16 +123,6 @@ governorDatumValidProperty = VoteLE0 -> -- vote < 0 return $ ProposalThresholds execute create le0 - CreateLEVote -> do - -- c > vote - nv <- taggedInteger (0, untag create - 1) - ne <- taggedInteger (untag nv + 1, 1000000000) - return $ ProposalThresholds ne create nv - ExecuteLVote -> do - -- vote >= execute - ne <- taggedInteger (0, untag vote) - nc <- taggedInteger (0, untag vote) - return $ ProposalThresholds ne nc vote Correct -> do -- c <= vote < execute nv <- taggedInteger (0, untag execute - 1) @@ -197,7 +183,7 @@ governorMintingProperty = GovernorOutputNotFound -> referencedInput <> mintAmount 1 GovernorPolicyCorrect -> referencedInput <> outputToGov <> mintAmount 1 - return . buildMintingUnsafe $ inputs <> outputs <> comp + return . buildMintingUnsafe $ inputs <> outputs <> comp <> withMinting govSymbol expected :: ScriptContext -> Maybe () expected sc = diff --git a/agora-specs/Sample/Governor.hs b/agora-specs/Sample/Governor.hs deleted file mode 100644 index 44d0105..0000000 --- a/agora-specs/Sample/Governor.hs +++ /dev/null @@ -1,464 +0,0 @@ -{- | -Module : Sample.Governor -Maintainer : connor@mlabs.city -Description: Sample based testing for Governor utxos - -This module tests primarily the happy path for Governor interactions --} -module Sample.Governor ( - createProposal, - mutateState, - mintGATs, - mintGST, -) where - -import Agora.Effect.NoOp (noOpValidator) -import Agora.Governor (GovernorDatum (..), getNextProposalId) -import Agora.Proposal ( - ProposalDatum (..), - ProposalId (..), - ProposalStatus (..), - ProposalVotes (..), - ResultTag (..), - emptyVotesFor, - ) -import Agora.Proposal qualified as P (ProposalDatum (proposalId)) -import Agora.Proposal.Time ( - ProposalStartingTime (ProposalStartingTime), - ProposalTimingConfig (..), - ) -import Agora.Stake (ProposalLock (..), Stake (..), StakeDatum (..)) -import Data.Default.Class (Default (def)) -import Data.Tagged (Tagged (..), untag) -import Plutarch.Api.V1 (mkValidator, validatorHash) -import Plutarch.Context ( - MintingBuilder, - SpendingBuilder, - buildMintingUnsafe, - buildSpendingUnsafe, - fee, - input, - mint, - output, - script, - signedWith, - timeRange, - txId, - withDatum, - withRefIndex, - withSpending, - withTxId, - withValue, - ) -import PlutusLedgerApi.V1 ( - BuiltinData (BuiltinData), - Data (I), - Datum (Datum), - ScriptContext, - TokenName (TokenName), - TxOutRef (txOutRefId), - Validator, - ValidatorHash (..), - ) -import PlutusLedgerApi.V1.Value (AssetClass (AssetClass)) -import PlutusLedgerApi.V1.Value qualified as Value ( - assetClassValue, - singleton, - ) -import PlutusTx.AssocMap qualified as AssocMap ( - empty, - fromList, - singleton, - ) -import Sample.Shared ( - authorityTokenSymbol, - govAssetClass, - govValidatorHash, - gstUTXORef, - minAda, - proposalPolicySymbol, - proposalStartingTimeFromTimeRange, - proposalValidatorHash, - signer, - signer2, - stake, - stakeAssetClass, - stakeValidatorHash, - ) -import Test.Util (closedBoundedInterval, toDatumHash) - --- | Unit datum -unitDatum :: Datum -unitDatum = Datum . BuiltinData $ I 0 -- This could be anything, really. It doesn't matter. - -{- | A valid 'ScriptContext' for minting GST. - - - Only the minting policy will be ran in the transaction. - - An arbitrary UTXO is spent to create the token. - - - We call this the "witness" UTXO. - - This UTXO is referenced in the 'Agora.Governor.Governor' parameter - - The minting policy should only be ran once its life time, - cause the GST cannot be minted twice or burnt. - - - The output UTXO must carry a valid 'GovernorDatum'. - - It's worth noticing that the transaction should send the GST to the governor validator, - but unfortunately we can't check it in the policy. The GST will stay at the address of - the governor validator forever once the token is under control of the said validator. - - TODO: tag the output UTXO with the target address. --} -mintGST :: ScriptContext -mintGST = - let gst = Value.assetClassValue govAssetClass 1 - - governorOutputDatum :: GovernorDatum - governorOutputDatum = - GovernorDatum - { proposalThresholds = def - , nextProposalId = ProposalId 0 - , proposalTimings = def - , createProposalTimeRangeMaxWidth = def - , maximumProposalsPerStake = 3 - } - - witness :: ValidatorHash - witness = "a926a9a72a0963f428e3252caa8354e655603996fb8892d6b8323fd072345924" - - builder :: MintingBuilder - builder = - mconcat - [ txId "90906d3e6b4d6dec2e747dcdd9617940ea8358164c7244694cfa39dec18bd9d4" - , signedWith signer - , mint gst - , input $ - script witness - . withTxId (txOutRefId gstUTXORef) - . withRefIndex 0 - , output $ - script govValidatorHash - . withValue (gst <> minAda) - . withDatum governorOutputDatum - ] - in buildMintingUnsafe builder - -{- | A valid script context to create a proposal. - - Three component will run in the transaction: - TODO: mention redeemers - - - Governor validator - - Stake validator - - Proposal policy - - The components will ensure: - - - The governor state UTXO is spent - - - A new UTXO is paid back to governor validator, which carries the GST. - - The proposal id in the state datum is advanced. - - - A new UTXO is sent to the proposal validator - - - The UTXO contains a newly minted proposal state token. - - It also carries a legal proposal state datum, whose status is set to 'Agora.Proposal.Draft'. - - - A stake is spent to create a proposal - - - The stake owner must sign the transaction. - - The output stake must paid back to the stake validator. - - The output stake is locked by the newly created proposal. --} -createProposal :: ScriptContext -createProposal = - let pst = Value.singleton proposalPolicySymbol "" 1 - gst = Value.assetClassValue govAssetClass 1 - sst = Value.assetClassValue stakeAssetClass 1 - stackedGTs = 424242424242 - thisProposalId = ProposalId 0 - - governorInputDatum :: GovernorDatum - governorInputDatum = - GovernorDatum - { proposalThresholds = def - , nextProposalId = thisProposalId - , proposalTimings = def - , createProposalTimeRangeMaxWidth = def - , maximumProposalsPerStake = 3 - } - - effects = - AssocMap.fromList - [ (ResultTag 0, AssocMap.empty) - , (ResultTag 1, AssocMap.empty) - ] - proposalDatum :: ProposalDatum - proposalDatum = - ProposalDatum - { P.proposalId = ProposalId 0 - , effects = effects - , status = Draft - , cosigners = [signer] - , thresholds = def - , votes = emptyVotesFor effects - , timingConfig = def - , startingTime = proposalStartingTimeFromTimeRange validTimeRange - } - - stakeInputDatum :: StakeDatum - stakeInputDatum = - StakeDatum - { stakedAmount = Tagged stackedGTs - , owner = signer - , lockedBy = [] - } - - governorOutputDatum :: GovernorDatum - governorOutputDatum = governorInputDatum {nextProposalId = getNextProposalId thisProposalId} - - proposalLocks :: [ProposalLock] - proposalLocks = - [ Created thisProposalId - ] - stakeOutputDatum :: StakeDatum - stakeOutputDatum = stakeInputDatum {lockedBy = proposalLocks} - - validTimeRange = closedBoundedInterval 10 15 - - builder :: SpendingBuilder - builder = - mconcat - [ txId "1ffb9669335c908d9a4774a4bf7aa7bfafec91d015249b4138bc83fde4a3330a" - , fee $ Value.singleton "" "" 2 - , timeRange $ closedBoundedInterval 10 15 - , signedWith signer - , mint pst - , input $ - script govValidatorHash - . withValue gst - . withDatum governorInputDatum - . withTxId "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865" - , input $ - script stakeValidatorHash - . withValue (sst <> Value.assetClassValue (untag stake.gtClassRef) stackedGTs) - . withDatum stakeInputDatum - . withTxId "4262bbd0b3fc926b74eaa8abab5def6ce5e6b94f19cf221c02a16e7da8cd470f" - , output $ - script proposalValidatorHash - . withValue (pst <> minAda) - . withDatum proposalDatum - , output $ - script govValidatorHash - . withValue (gst <> minAda) - . withDatum governorOutputDatum - , output $ - script stakeValidatorHash - . withValue (sst <> Value.assetClassValue (untag stake.gtClassRef) stackedGTs <> minAda) - . withDatum stakeOutputDatum - , withSpending $ - script govValidatorHash - . withValue gst - . withDatum governorInputDatum - ] - in buildSpendingUnsafe builder - -{- This script context should be a valid transaction for minting authority for the effect scrips. - - The following components will run: - - - Governor validator - - Authority policy - - Proposal validator - - There should be only one proposal the transaction. - The validity of the proposal will be checked: - - - It's in 'Agora.Proposal.Locked' state. - - It has a 'winner' effect group, meaning that the votes meet the requirements. - - The system will ensure that for every effect scrips in said effect group, - a newly minted GAT is sent to the corresponding effect, and properly tagged. --} -mintGATs :: ScriptContext -mintGATs = - let pst = Value.singleton proposalPolicySymbol "" 1 - gst = Value.assetClassValue govAssetClass 1 - gat = Value.assetClassValue atAssetClass 1 - - mockEffect :: Validator - mockEffect = mkValidator $ noOpValidator "" - mockEffectHash :: ValidatorHash - mockEffectHash = validatorHash mockEffect - mockEffectOutputDatum :: Datum - mockEffectOutputDatum = unitDatum - atTokenName :: TokenName - atTokenName = TokenName hash - where - ValidatorHash hash = mockEffectHash - atAssetClass :: AssetClass - atAssetClass = AssetClass (authorityTokenSymbol, atTokenName) - - governorInputDatum :: GovernorDatum - governorInputDatum = - GovernorDatum - { proposalThresholds = def - , nextProposalId = ProposalId 5 - , proposalTimings = def - , createProposalTimeRangeMaxWidth = def - , maximumProposalsPerStake = 3 - } - - effects = - AssocMap.fromList - [ (ResultTag 0, AssocMap.empty) - , (ResultTag 1, AssocMap.singleton mockEffectHash $ toDatumHash mockEffectOutputDatum) - ] - proposalVotes :: ProposalVotes - proposalVotes = - ProposalVotes $ - AssocMap.fromList - [ (ResultTag 0, 100) - , (ResultTag 1, 2000) -- The winner - ] - proposalInputDatum :: ProposalDatum - proposalInputDatum = - ProposalDatum - { P.proposalId = ProposalId 0 - , effects = effects - , status = Locked - , cosigners = [signer, signer2] - , thresholds = def - , votes = proposalVotes - , timingConfig = def - , startingTime = ProposalStartingTime 10 - } - - governorOutputDatum :: GovernorDatum - governorOutputDatum = governorInputDatum - - proposalOutputDatum :: ProposalDatum - proposalOutputDatum = proposalInputDatum {status = Finished} - - validTimeRange = - closedBoundedInterval - ((def :: ProposalTimingConfig).lockingTime + 11) - ((def :: ProposalTimingConfig).executingTime - 11) - - builder :: SpendingBuilder - builder = - mconcat - [ txId "ff755f613c1f7487dfbf231325c67f481f7a97e9faf4d8b09ad41176fd65cbe7" - , signedWith signer - , signedWith signer2 - , timeRange validTimeRange - , fee (Value.singleton "" "" 2) - , mint gat - , input $ - script govValidatorHash - . withValue gst - . withDatum governorInputDatum - . withTxId "4355a46b19d348dc2f57c046f8ef63d4538ebb936000f3c9ee954a27460dd865" - , input $ - script proposalValidatorHash - . withValue pst - . withDatum proposalInputDatum - . withTxId "11b2162f267614b803761032b6333040fc61478ae788c088614ee9487ab0c1b7" - , output $ - script govValidatorHash - . withValue (gst <> minAda) - . withDatum governorOutputDatum - , output $ - script proposalValidatorHash - . withValue (pst <> minAda) - . withDatum proposalOutputDatum - , output $ - script mockEffectHash - . withValue (gat <> minAda) - . withDatum mockEffectOutputDatum - , withSpending $ - script govValidatorHash - . withValue gst - . withDatum governorInputDatum - ] - in buildSpendingUnsafe builder - -{- | A valid script context for changing the state datum of the governor. - - In this case, the following components will run: - - * Governor validator - * Effect script - - The effect script should carry an valid tagged authority token, - and said token will be burnt in the transaction. We use 'noOpValidator' - here as a mock effect, so no actual change is done to the governor state. - TODO: use 'Agora.Effect.GovernorMutation.mutateGovernorEffect' as the mock effect in the future. - - The governor will ensure the new governor state is valid. --} -mutateState :: ScriptContext -mutateState = - let gst = Value.assetClassValue govAssetClass 1 - gat = Value.assetClassValue atAssetClass 1 - burntGAT = Value.assetClassValue atAssetClass (-1) - - -- TODO: Use the *real* effect, see https://github.com/Liqwid-Labs/agora/pull/62 - mockEffect :: Validator - mockEffect = mkValidator $ noOpValidator "" - mockEffectHash :: ValidatorHash - mockEffectHash = validatorHash mockEffect - atTokenName :: TokenName - atTokenName = TokenName hash - where - ValidatorHash hash = mockEffectHash - atAssetClass :: AssetClass - atAssetClass = AssetClass (authorityTokenSymbol, atTokenName) - mockEffectInputDatum :: Datum - mockEffectInputDatum = unitDatum - mockEffectOutputDatum :: Datum - mockEffectOutputDatum = mockEffectInputDatum - - governorInputDatum :: GovernorDatum - governorInputDatum = - GovernorDatum - { proposalThresholds = def - , nextProposalId = ProposalId 5 - , proposalTimings = def - , createProposalTimeRangeMaxWidth = def - , maximumProposalsPerStake = 3 - } - - governorOutputDatum :: GovernorDatum - governorOutputDatum = governorInputDatum - - builder :: SpendingBuilder - builder = - mconcat - [ txId "9a12a605086a9f866731869a42d0558036fc739c74fea3849aa41562c015aaf9" - , signedWith signer - , mint burntGAT - , fee $ Value.singleton "" "" 2 - , input $ - script govValidatorHash - . withValue gst - . withDatum governorInputDatum - . withTxId "f867238a04597c99a0b9858746557d305025cca3b9f78ea14d5c88c4cfcf58ff" - , input $ - script mockEffectHash - . withValue gat - . withDatum mockEffectInputDatum - . withTxId "ecff06d7cf99089294569cc8b92609e44927278f9901730715d14634fbc10089" - , output $ - script govValidatorHash - . withValue (gst <> minAda) - . withDatum governorOutputDatum - , input $ - script mockEffectHash - . withValue minAda - . withDatum mockEffectOutputDatum - , withSpending $ - script govValidatorHash - . withValue gst - . withDatum governorInputDatum - ] - in buildSpendingUnsafe builder diff --git a/agora-specs/Sample/Governor/Initialize.hs b/agora-specs/Sample/Governor/Initialize.hs new file mode 100644 index 0000000..954d9cb --- /dev/null +++ b/agora-specs/Sample/Governor/Initialize.hs @@ -0,0 +1,270 @@ +{- | +Module : Sample.Governor.Initialize +Maintainer : connor@mlabs.city +Description: Generate sample data for testing the functionalities of minting GST. + +Sample and utilities for testing the functionalities of minting GST. +-} +module Sample.Governor.Initialize ( + mintGST, + Parameters (..), + totallyValidParameters, + invalidDatumTimingConfigParameters, + invalidDatumMaxTimeRangeWidthParameters, + invalidDatumThresholdsParameters, + withoutGovernorDatumParameters, + witnessNotPresentedParameters, + mintMoreThanOneGSTParameters, + mintGSTWithNoneEmptyNameParameters, + mkTestCase, +) where + +import Agora.Governor (Governor (..), GovernorDatum (..)) +import Agora.Governor.Scripts ( + governorPolicy, + governorSTAssetClassFromGovernor, + governorValidatorHash, + ) +import Agora.Proposal (ProposalId (..), ProposalThresholds (..)) +import Agora.Proposal.Time (MaxTimeRangeWidth (MaxTimeRangeWidth), ProposalTimingConfig (ProposalTimingConfig)) +import Data.Default (Default (..)) +import Plutarch.Api.V1 (mintingPolicySymbol, mkMintingPolicy) +import Plutarch.Context ( + input, + mint, + output, + pubKey, + script, + signedWith, + txId, + withDatum, + withOutRef, + withValue, + ) +import PlutusLedgerApi.V1 ( + CurrencySymbol, + MintingPolicy, + TxOutRef (TxOutRef), + ValidatorHash, + ) +import PlutusLedgerApi.V1.Value (AssetClass (..)) +import PlutusLedgerApi.V1.Value qualified as Value +import Sample.Shared ( + minAda, + ) +import Sample.Shared qualified as Shared +import Test.Specification (SpecificationTree, testPolicy) +import Test.Util (CombinableBuilder, mkMinting, pubKeyHashes, sortValue) + +-- | The parameters that control the generation of the transaction. +data Parameters = Parameters + { datumThresholdsValid :: Bool + -- ^ Whether the 'GovernorDatum.proposalThresholds' field of the output + -- governor datum is valid or not. + , datumMaxTimeRangeWidthValid :: Bool + -- ^ Whether the 'GovernorDatum.maximumProposalsPerStake'field of the + -- output governor datum is valid or not. + , datumTimingConfigValid :: Bool + -- ^ Whether the 'GovernorDatum.proposalTimings'field of the output + -- governor datum is valid or not. + , withGovernorDatum :: Bool + , -- Whether the output GST UTxO will carry the governor datum. + presentWitness :: Bool + , -- Whether to spend the UTxO referenced by 'Governor.gstOutRef'. + mintMoreThanOneStateToken :: Bool + , -- More than one GST will be minted if this is set to true. + mintStateTokenWithName :: Bool + -- The token name of the GST won't be empty if this is set to true. + } + +-------------------------------------------------------------------------------- + +validGovernorOutputDatum :: GovernorDatum +validGovernorOutputDatum = + GovernorDatum + { proposalThresholds = def + , nextProposalId = ProposalId 0 + , proposalTimings = def + , createProposalTimeRangeMaxWidth = def + , maximumProposalsPerStake = 3 + } + +invalidProposalThresholds :: ProposalThresholds +invalidProposalThresholds = ProposalThresholds (-1) (-1) (-1) + +invalidMaxTimeRangeWidth :: MaxTimeRangeWidth +invalidMaxTimeRangeWidth = MaxTimeRangeWidth 0 + +invalidProposalTimings :: ProposalTimingConfig +invalidProposalTimings = ProposalTimingConfig (-1) (-1) (-1) (-1) + +witnessRef :: TxOutRef +witnessRef = TxOutRef "b0353c22b0bd6c5296a8eef160ba25d90b5dc82a9bb8bdaa6823ffc19515d6ad" 0 + +governor :: Governor +governor = + Shared.governor + { gstOutRef = witnessRef + } + +govAssetClass :: AssetClass +govAssetClass = governorSTAssetClassFromGovernor governor + +govValidatorHash :: ValidatorHash +govValidatorHash = governorValidatorHash governor + +govPolicy :: MintingPolicy +govPolicy = mkMintingPolicy (governorPolicy governor) + +govSymbol :: CurrencySymbol +govSymbol = mintingPolicySymbol govPolicy + +-------------------------------------------------------------------------------- + +mintGST :: forall b. CombinableBuilder b => Parameters -> b +mintGST ps = builder + where + gstAC = + if ps.mintStateTokenWithName + then AssetClass (govSymbol, "12345") + else govAssetClass + gstCount = + if ps.mintMoreThanOneStateToken + then 10 + else 1 + gst = Value.assetClassValue gstAC gstCount + + --- + + governorOutputDatum = + let th = + if ps.datumThresholdsValid + then def + else invalidProposalThresholds + trw = + if ps.datumMaxTimeRangeWidthValid + then def + else invalidMaxTimeRangeWidth + ptc = + if ps.datumTimingConfigValid + then def + else invalidProposalTimings + in validGovernorOutputDatum + { proposalThresholds = th + , proposalTimings = ptc + , createProposalTimeRangeMaxWidth = trw + } + + governorValue = sortValue $ gst <> minAda + + --- + + witnessValue = minAda + witnessPubKey = head pubKeyHashes + + --- + + witnessBuilder = + if ps.presentWitness + then + mconcat + [ input $ + pubKey witnessPubKey + . withValue witnessValue + . withOutRef witnessRef + , output $ + pubKey witnessPubKey + . withValue witnessValue + ] + else mempty + + --- + + govBuilder = + let datum = + if ps.withGovernorDatum + then withDatum governorOutputDatum + else id + in output $ + script govValidatorHash + . withValue governorValue + . datum + -- + builder = + mconcat + [ txId "986b756ffb1c9839fc8d0b22a308ac91d5b5d0ebbfa683a47588c8a5cf70b5af" + , signedWith (pubKeyHashes !! 1) + , mint gst + , govBuilder + , witnessBuilder + ] + +-------------------------------------------------------------------------------- + +totallyValidParameters :: Parameters +totallyValidParameters = + Parameters + { datumThresholdsValid = True + , datumMaxTimeRangeWidthValid = True + , datumTimingConfigValid = True + , withGovernorDatum = True + , presentWitness = True + , mintMoreThanOneStateToken = False + , mintStateTokenWithName = False + } + +invalidDatumThresholdsParameters :: Parameters +invalidDatumThresholdsParameters = + totallyValidParameters + { datumThresholdsValid = False + } + +invalidDatumMaxTimeRangeWidthParameters :: Parameters +invalidDatumMaxTimeRangeWidthParameters = + totallyValidParameters + { datumMaxTimeRangeWidthValid = False + } + +invalidDatumTimingConfigParameters :: Parameters +invalidDatumTimingConfigParameters = + totallyValidParameters + { datumTimingConfigValid = False + } + +withoutGovernorDatumParameters :: Parameters +withoutGovernorDatumParameters = + totallyValidParameters + { withGovernorDatum = False + } + +witnessNotPresentedParameters :: Parameters +witnessNotPresentedParameters = + totallyValidParameters + { presentWitness = False + } + +mintMoreThanOneGSTParameters :: Parameters +mintMoreThanOneGSTParameters = + totallyValidParameters + { mintMoreThanOneStateToken = True + } + +mintGSTWithNoneEmptyNameParameters :: Parameters +mintGSTWithNoneEmptyNameParameters = + totallyValidParameters + { mintStateTokenWithName = True + } + +-------------------------------------------------------------------------------- + +{- | Create a test tree that runs the governor policy to test the initialization + of the governor. +-} +mkTestCase :: String -> Parameters -> Bool -> SpecificationTree +mkTestCase name ps valid = + testPolicy + valid + name + (governorPolicy governor) + () + (mkMinting mintGST ps govSymbol) diff --git a/agora-specs/Sample/Governor/Mutate.hs b/agora-specs/Sample/Governor/Mutate.hs new file mode 100644 index 0000000..735aae1 --- /dev/null +++ b/agora-specs/Sample/Governor/Mutate.hs @@ -0,0 +1,261 @@ +module Sample.Governor.Mutate ( + -- * Testing Utilities + GovernorOutputDatumValidity (..), + GATValidity (..), + GovernorParameters (..), + MockEffectParameters (..), + ParameterBundle (..), + + -- * Testing Utilities + Validity (..), + mutate, + mkTestCase, + + -- * Parameters Bundles + totallyValidBundle, + invalidBundles, +) where + +import Agora.Effect.NoOp (noOpValidator) +import Agora.Governor (GovernorDatum (..), GovernorRedeemer (MutateGovernor)) +import Agora.Governor.Scripts (governorValidator) +import Agora.Proposal (ProposalId (ProposalId), ProposalThresholds (..)) +import Agora.Utils (validatorHashToTokenName) +import Data.Default (def) +import Plutarch.Api.V1 (PValidator, mkValidator, validatorHash) +import Plutarch.Context ( + input, + mint, + output, + pubKey, + script, + withDatum, + withOutRef, + withValue, + ) +import PlutusLedgerApi.V1 ( + Data, + TxOutRef (TxOutRef), + ValidatorHash, + Value, + toData, + ) +import PlutusLedgerApi.V1.Value qualified as Value +import Sample.Shared ( + authorityTokenSymbol, + govAssetClass, + govValidatorHash, + governor, + minAda, + ) +import Test.Specification (SpecificationTree, testValidator) +import Test.Util (CombinableBuilder, mkSpending, pubKeyHashes, sortValue, validatorHashes, withOptional) + +-------------------------------------------------------------------------------- + +-- | Represent the validity property of the governor output datum. +data GovernorOutputDatumValidity + = DatumValid + | ValueInvalid + | WrongType + | NoDatum + deriving stock (Bounded, Enum) + +-- | Represent the validity property of the authority token UTxO. +data GATValidity + = GATValid + | WrongTag + | NoGAT + deriving stock (Bounded, Enum) + +data GovernorParameters = GovernorParameters + { governorOutputDatumValidity :: GovernorOutputDatumValidity + , stealGST :: Bool + -- ^ Send the GST to somewhere else other than the govenor validator. + } + +data MockEffectParameters = MockEffectParameters + { gatValidity :: GATValidity + , burnGAT :: Bool + -- ^ Whether to burn the GAT in the transaction or not. + } + +data ParameterBundle = ParameterBundle + { governorParameters :: GovernorParameters + , mockEffectParameters :: MockEffectParameters + } + +newtype Validity = Validity {forGovernorValidator :: Bool} + +-------------------------------------------------------------------------------- + +governorInputDatum :: GovernorDatum +governorInputDatum = + GovernorDatum + { proposalThresholds = def + , nextProposalId = ProposalId 0 + , proposalTimings = def + , createProposalTimeRangeMaxWidth = def + , maximumProposalsPerStake = 3 + } + +mkGovernorOutputDatum :: + GovernorOutputDatumValidity -> + Maybe Data +mkGovernorOutputDatum DatumValid = + Just $ + toData $ + governorInputDatum + { maximumProposalsPerStake = 4 + } +mkGovernorOutputDatum ValueInvalid = + let invalidProposalThresholds = + ProposalThresholds + { execute = -1 + , create = -1 + , vote = -1 + } + in Just $ + toData $ + governorInputDatum + { proposalThresholds = + invalidProposalThresholds + } +mkGovernorOutputDatum WrongType = Just $ toData () +mkGovernorOutputDatum NoDatum = Nothing + +governorRef :: TxOutRef +governorRef = + TxOutRef + "6cce6dfbb697f9e2c4fe9786bb576eb7bd6cbcf7801a4ba13d596006c2d5b957" + 1 + +governorRedeemer :: GovernorRedeemer +governorRedeemer = MutateGovernor + +mkGovernorBuilder :: forall b. CombinableBuilder b => GovernorParameters -> b +mkGovernorBuilder ps = + let gst = Value.assetClassValue govAssetClass 1 + value = sortValue $ gst <> minAda + gstOutput = + if ps.stealGST + then pubKey $ head pubKeyHashes + else script govValidatorHash + withGSTDatum = + withOptional withDatum $ + mkGovernorOutputDatum ps.governorOutputDatumValidity + in mconcat + [ input $ + script govValidatorHash + . withDatum governorInputDatum + . withValue value + . withOutRef governorRef + , output $ + gstOutput + . withGSTDatum + . withValue value + ] + +-------------------------------------------------------------------------------- + +mockEffectValidator :: ClosedTerm PValidator +mockEffectValidator = noOpValidator authorityTokenSymbol + +mockEffectValidatorHash :: ValidatorHash +mockEffectValidatorHash = validatorHash $ mkValidator mockEffectValidator + +mkGATValue :: GATValidity -> Integer -> Value +mkGATValue NoGAT _ = mempty +mkGATValue v q = + let gatOwner = case v of + GATValid -> mockEffectValidatorHash + WrongTag -> head validatorHashes + in Value.singleton + authorityTokenSymbol + (validatorHashToTokenName gatOwner) + q + +mkMockEffectBuilder :: forall b. CombinableBuilder b => MockEffectParameters -> b +mkMockEffectBuilder ps = + let mkGATValue' = mkGATValue ps.gatValidity + inputValue = mkGATValue' 1 + outputValue = inputValue <> burnt + burnt = + if ps.burnGAT + then mkGATValue' (-1) + else mempty + in mconcat + [ mint burnt + , input $ + script mockEffectValidatorHash + . withValue inputValue + , output $ + script mockEffectValidatorHash + . withValue outputValue + ] + +-------------------------------------------------------------------------------- + +mutate :: forall b. CombinableBuilder b => ParameterBundle -> b +mutate pb = + mconcat + [ mkGovernorBuilder pb.governorParameters + , mkMockEffectBuilder pb.mockEffectParameters + ] + +-------------------------------------------------------------------------------- + +-- | Run the governor to test the mutation functionality. +mkTestCase :: String -> ParameterBundle -> Validity -> SpecificationTree +mkTestCase name pb (Validity forGov) = + testValidator + forGov + name + (governorValidator governor) + governorInputDatum + governorRedeemer + (mkSpending mutate pb governorRef) + +-------------------------------------------------------------------------------- + +-- | The only one valid combination of all the parameters. +totallyValidBundle :: ParameterBundle +totallyValidBundle = + ParameterBundle + { governorParameters = + GovernorParameters + { governorOutputDatumValidity = DatumValid + , stealGST = False + } + , mockEffectParameters = + MockEffectParameters + { gatValidity = GATValid + , burnGAT = True + } + } + +-------------------------------------------------------------------------------- + +{- | All the invalid combination of the parameters. + TODO: use 'Gen'? +-} +invalidBundles :: [ParameterBundle] +invalidBundles = do + gdv <- enumFrom ValueInvalid + sg <- [True, False] + gtv <- enumFrom WrongTag + bgt <- [True, False] + + pure $ + ParameterBundle + { governorParameters = + GovernorParameters + { governorOutputDatumValidity = gdv + , stealGST = sg + } + , mockEffectParameters = + MockEffectParameters + { gatValidity = gtv + , burnGAT = bgt + } + } diff --git a/agora-specs/Sample/Proposal/Advance.hs b/agora-specs/Sample/Proposal/Advance.hs index 73c2ab6..91fa17d 100644 --- a/agora-specs/Sample/Proposal/Advance.hs +++ b/agora-specs/Sample/Proposal/Advance.hs @@ -6,16 +6,46 @@ Description: Generate sample data for testing the functionalities of advancing p Sample and utilities for testing the functionalities of advancing proposals. -} module Sample.Proposal.Advance ( - advanceToNextStateInTimeParameters, - advanceToFailedStateDueToTimeoutParameters, - insufficientVotesParameters, - insufficientCosignsParameters, - advanceFromFinishedParameters, - invalidOutputStakeParameters, + -- * Parameters + ParameterBundle (..), + GovernorParameters (..), + AuthorityTokenParameters (..), + ProposalParameters (..), + StakeParameters (..), + Winner (..), + + -- * Testing Utilities + Validity (..), + advance, mkTestTree, - Parameters (..), + mkTestTree', + + -- * Parameter Bundles + mkValidToNextStateBundle, + mkValidToNextStateBundles, + mkValidToFailedStateBundles, + mkInsufficientVotesBundle, + mkAmbiguousWinnerBundle, + mkFromFinishedBundles, + mkInsufficientCosignsBundle, + mkToNextStateTooLateBundles, + mkInvalidOutputStakeBundles, + mkMintGATsForWrongEffectsBundle, + mkNoGATMintedBundle, + mkGATsWithWrongDatumBundle, + mkMintGATsWithoutTagBundle, + mkBadGovernorOutputDatumBundle, ) where +import Agora.AuthorityToken ( + AuthorityToken (AuthorityToken), + authorityTokenPolicy, + ) +import Agora.Governor ( + GovernorDatum (..), + GovernorRedeemer (MintGATs), + ) +import Agora.Governor.Scripts (governorValidator) import Agora.Proposal ( ProposalDatum (..), ProposalId (ProposalId), @@ -36,272 +66,543 @@ import Agora.Proposal.Time ( votingTime ), ) -import Agora.SafeMoney (GTTag) import Agora.Stake ( - ProposalLock (..), Stake (gtClassRef), StakeDatum (..), StakeRedeemer (WitnessStake), ) import Agora.Stake.Scripts (stakeValidator) -import Data.Coerce (coerce) +import Agora.Utils (validatorHashToTokenName) +import Control.Monad.State (execState, modify, when) import Data.Default (def) import Data.List (sort) +import Data.Maybe (catMaybes, fromJust) import Data.Tagged (Tagged (..), untag) import Plutarch.Context ( - BaseBuilder, - buildTxInfoUnsafe, input, + mint, output, script, signedWith, timeRange, - txId, withDatum, withOutRef, - withTxId, withValue, ) +import Plutarch.Lift (PLifted, PUnsafeLiftDecl) import PlutusLedgerApi.V1 ( DatumHash, POSIXTime, POSIXTimeRange, PubKeyHash, - ScriptContext (ScriptContext), - ScriptPurpose (Spending), - TxInfo, TxOutRef (TxOutRef), ValidatorHash, - always, ) +import PlutusLedgerApi.V1.Value (AssetClass (..)) import PlutusLedgerApi.V1.Value qualified as Value import PlutusTx.AssocMap qualified as AssocMap -import Sample.Proposal.Shared (proposalTxRef, stakeTxRef) +import Sample.Proposal.Shared ( + governorTxRef, + proposalTxRef, + stakeTxRef, + ) import Sample.Shared ( + authorityTokenSymbol, + govAssetClass, + govValidatorHash, minAda, proposalPolicySymbol, proposalValidatorHash, + signer, stake, stakeAssetClass, stakeValidatorHash, ) import Sample.Shared qualified as Shared -import Test.Specification (SpecificationTree, group, testValidator) -import Test.Util (closedBoundedInterval, pubKeyHashes, sortValue, updateMap) +import Test.Specification ( + SpecificationTree, + group, + testPolicy, + testValidator, + ) +import Test.Util ( + CombinableBuilder, + closedBoundedInterval, + datumHash, + groupsOfN, + mkMinting, + mkSpending, + pubKeyHashes, + sortValue, + toDatum, + updateMap, + validatorHashes, + ) --- | Parameters for state transition of proposals. -data Parameters = Parameters - { fromStatus :: ProposalStatus - -- ^ Initial state of the proposal. - , toStatus :: ProposalStatus - -- ^ Next state of the proposal. - , votes :: ProposalVotes - -- ^ Votes. - , includeAllStakes :: Bool - -- ^ Whether to add an extra cosigner without stake or not. - , validTimeRange :: POSIXTimeRange - -- ^ Valid time range of the transaction. - , alterOutputStakes :: Bool - -- ^ Whether to alter th output stakes or not. - , 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. +{- | A bunch of parameters that control the generation of the transaction + context. +-} +data ParameterBundle = ParameterBundle + { proposalParameters :: ProposalParameters + -- ^ Parameters related to the the advancing proposal. + , stakeParameters :: StakeParameters + -- ^ Parameters related to stakes. + , governorParameters :: Maybe GovernorParameters + -- ^ Parameters related to GST moving. If set to 'Nothing', the GST won't + -- be moved, thus the governor validator won't be run in 'mkTestTree'. + , authorityTokenParameters :: Maybe AuthorityTokenParameters + -- ^ Parameters related to GAT minting. If set to 'Nothing', no GAT will + -- be minted, thus the GAT minting policy won't be run in 'mkTestTree'. + , transactionTimeRange :: POSIXTimeRange + -- ^ The value of 'TxInfo.txInfoValidRange', valid range of the generated + -- transaction. + , extraSignature :: Maybe PubKeyHash + -- ^ An extra signator. Intended to be used when + -- 'StakeParametersstakeParameters.transactionSignedByOwners' is set to + -- false. } ---- +-- | Everything about the generated governor stuff. +newtype GovernorParameters = GovernorParameters + { invalidGovernorOutputDatum :: Bool + -- ^ The output governor datum will be changed. + } + +-- | Everything about the generated authority token stuff. +data AuthorityTokenParameters = forall + (datum :: Type) + (pdatum :: S -> Type). + ( PUnsafeLiftDecl pdatum + , PLifted pdatum ~ datum + , PIsData pdatum + ) => + AuthorityTokenParameters + { mintGATsFor :: [ValidatorHash] + -- ^ GATs will be minted and sent to the given group of effects. + , carryDatum :: Maybe datum + -- ^ The datum that GAT UTxOs will be carrying. + , invalidTokenName :: Bool + -- ^ If set to true, GATs won't be tagged by their corresponding effect + -- hashes. + } + +-- | Represent the winning effect group(s). +data Winner + = -- | Only one effect at the given index has the highest votes. + EffectAt Index + | -- | All the effects have the same highest votes. + All + +-- | Everything about the generated proposal stuff. +data ProposalParameters = ProposalParameters + { fromStatus :: ProposalStatus + -- ^ What status is the proposal advancing from + , toStatus :: ProposalStatus + -- ^ What status is the proposal advancing to + , effectList :: [AssocMap.Map ValidatorHash DatumHash] + -- ^ The effect groups of the proposal. A neutral effect group is not + -- required here. + , winnerAndVotes :: Maybe (Winner, Integer) + -- ^ Specify the effect group(s) that have the highest votes, and the value + -- of the highest votes. + , numCosigners :: NumStake + -- ^ The number of cosigners. + , invalidProposalOutputDatum :: Bool + -- ^ Whether to make the proposal output datum invalid or not. + } + +-- | Everything about the generated stake stuff. +data StakeParameters = StakeParameters + { numStake :: NumStake + , perStakeGTs :: Integer + , transactionSignedByOwners :: Bool + , invalidStakeOutputDatum :: Bool + } + +-- | Represent the number of stakes or the number of the cosigners. +type NumStake = Int + +-- | Represent an index. +type Index = Int + +{- | The validity of the generated transacrion for variuos componets. + 'True' means valid, 'False' means invalid. +-} +data Validity = Validity + { forProposalValidator :: Bool + , forStakeValidator :: Bool + , forGovernorValidator :: Maybe Bool + , forAuthorityTokenPolicy :: Maybe Bool + } + +-------------------------------------------------------------------------------- + +-- * Proposal + +-- | Mock cosigners. +mkCosigners :: NumStake -> [PubKeyHash] +mkCosigners = sort . flip take pubKeyHashes + +-- | Allocate the result tag for the effect at the given index. +outcomeIdxToResultTag :: Index -> ResultTag +outcomeIdxToResultTag = ResultTag . fromIntegral + +-- | Add a neutral effect group and allocate result tags for the effect groups. +mkEffects :: + ProposalParameters -> + AssocMap.Map ResultTag (AssocMap.Map ValidatorHash DatumHash) +mkEffects ps = + let resultTags = map ResultTag [0 ..] + neutralEffect = AssocMap.empty + finalEffects = ps.effectList <> [neutralEffect] + in AssocMap.fromList $ zip resultTags finalEffects + +-- | Set the votes of the winning group(s). +setWinner :: (Winner, Integer) -> ProposalVotes -> ProposalVotes +setWinner (All, votes) (ProposalVotes m) = + ProposalVotes $ AssocMap.mapMaybe (const $ Just votes) m +setWinner (EffectAt winnerIdx, votes) (ProposalVotes m) = + let winnerResultTag = outcomeIdxToResultTag winnerIdx + in ProposalVotes $ updateMap (const $ Just votes) winnerResultTag m + +-- | Mock votes for the proposal, given the parameters. +mkVotes :: + ProposalParameters -> + ProposalVotes +mkVotes ps = + let effects = mkEffects ps + emptyVotes = emptyVotesFor effects + in maybe emptyVotes (`setWinner` emptyVotes) (ps.winnerAndVotes) + +-- | The starting time of every generated proposal. +proposalStartingTime :: POSIXTime +proposalStartingTime = 0 + +-- | Create the input proposal datum given the parameters. +mkProposalInputDatum :: ProposalParameters -> ProposalDatum +mkProposalInputDatum ps = + let effects = mkEffects ps + votes = mkVotes ps + st = ProposalStartingTime proposalStartingTime + in ProposalDatum + { proposalId = ProposalId 0 + , effects = effects + , status = ps.fromStatus + , cosigners = mkCosigners ps.numCosigners + , thresholds = def + , votes = votes + , timingConfig = def + , startingTime = st + } + +-- | Create the output proposal datum given the parameters. +mkProposalOutputDatum :: ProposalParameters -> ProposalDatum +mkProposalOutputDatum ps = + let inputDatum = mkProposalInputDatum ps + outputCosigners = + if ps.invalidProposalOutputDatum + then [] + else inputDatum.cosigners + in inputDatum + { status = ps.toStatus + , cosigners = outputCosigners + } -- | 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 - [ (ResultTag 0, AssocMap.empty) - , (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. +{- | Create a context builder that contains all the information about the + input/output of the proposal validator, given the paramters. -} -proposalStartingTime :: POSIXTime -proposalStartingTime = 0 +mkProposalBuilder :: forall b. CombinableBuilder b => ProposalParameters -> b +mkProposalBuilder ps = + let pst = Value.singleton proposalPolicySymbol "" 1 + value = sortValue $ minAda <> pst + in mconcat + [ input $ + script proposalValidatorHash + . withOutRef proposalRef + . withDatum (mkProposalInputDatum ps) + . withValue value + , output $ + script proposalValidatorHash + . withDatum (mkProposalOutputDatum ps) + . withValue value + ] ---- - --- | Create the input proposal datum given the parameters. -mkProposalInputDatum :: Parameters -> ProposalDatum -mkProposalInputDatum ps = - ProposalDatum - { proposalId = ProposalId 0 - , effects = defEffects - , status = ps.fromStatus - , cosigners = mkStakeOwners ps - , thresholds = def - , votes = ps.votes - , timingConfig = def - , startingTime = ProposalStartingTime proposalStartingTime - } - --- | Create the input stake datums given the parameters. -mkStakeInputDatums :: Parameters -> [StakeDatum] -mkStakeInputDatums ps = - map - ( \pk -> - StakeDatum - { stakedAmount = ps.perStakeGTs - , owner = pk - , lockedBy = existingLocks - } - ) - $ mkStakeOwners ps - where - existingLocks :: [ProposalLock] - existingLocks = - [ 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 +{- | The proposal 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 +-------------------------------------------------------------------------------- + +-- * Stake + +-- Mock owners of the stakes. +mkStakeOwners :: NumStake -> [PubKeyHash] +mkStakeOwners = mkCosigners + +-- | Create the input stake datums given the parameters. +mkStakeInputDatums :: StakeParameters -> [StakeDatum] +mkStakeInputDatums ps = + let template = + StakeDatum + { stakedAmount = Tagged ps.perStakeGTs + , owner = "" + , lockedBy = [] + } + in (\owner -> template {owner = owner}) + <$> mkStakeOwners ps.numStake + +-- | Create the output stake datums given the parameters. +mkStakeOutputDatums :: StakeParameters -> [StakeDatum] +mkStakeOutputDatums ps = + let inputDatums = mkStakeInputDatums ps + outputStakedAmount = + Tagged $ + if ps.invalidStakeOutputDatum + then ps.perStakeGTs * 10 + else ps.perStakeGTs + modify inp = inp {stakedAmount = outputStakedAmount} + in modify <$> inputDatums + +{- | Get the input stake datum given the index. The range of the index is + @[0, 'StakeParameters.numStake - 1']@ +-} +getStakeInputDatumAt :: StakeParameters -> Index -> StakeDatum +getStakeInputDatumAt ps = (!!) (mkStakeInputDatums ps) + +-- | Create the reference to a particular stake UTXO. +mkStakeRef :: Index -> TxOutRef +mkStakeRef = TxOutRef stakeTxRef . (+ 3) . fromIntegral + +{- | Create a context builder that contains all the inputs/outputs of the + stake validator. +-} +mkStakeBuilder :: forall b. CombinableBuilder b => StakeParameters -> b +mkStakeBuilder ps = + let perStakeValue = + sortValue $ + minAda + <> Value.assetClassValue stakeAssetClass 1 + <> Value.assetClassValue + (untag stake.gtClassRef) + ps.perStakeGTs + perStake idx i o = + let withSig = + if ps.transactionSignedByOwners + then signedWith i.owner + else mempty + in mconcat + [ withSig + , input $ + script stakeValidatorHash + . withOutRef (mkStakeRef idx) + . withValue perStakeValue + . withDatum i + , output $ + script stakeValidatorHash + . withValue perStakeValue + . withDatum o + ] + in mconcat $ + zipWith3 + perStake + [0 :: Index ..] + (mkStakeInputDatums ps) + (mkStakeOutputDatums ps) + +{- | The proposal 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 $ - take - (fromIntegral ps.stakeCount) - pubKeyHashes +-- * Governor ---- +-- | The input governor datum. +governorInputDatum :: GovernorDatum +governorInputDatum = + GovernorDatum + { proposalThresholds = def + , nextProposalId = ProposalId 42 + , proposalTimings = def + , createProposalTimeRangeMaxWidth = def + , maximumProposalsPerStake = 3 + } + +-- | Create the output governor datum given the parameters. +mkGovernorOutputDatum :: GovernorParameters -> GovernorDatum +mkGovernorOutputDatum ps = + if ps.invalidGovernorOutputDatum + then governorInputDatum {maximumProposalsPerStake = 15} + else governorInputDatum + +-- | Reference to the governor UTXO. +governorRef :: TxOutRef +governorRef = TxOutRef governorTxRef 2 + +{- | Create a context builder that contains the input and the output of the + governor validator. +-} +mkGovernorBuilder :: forall b. CombinableBuilder b => GovernorParameters -> b +mkGovernorBuilder ps = + let gst = Value.assetClassValue govAssetClass 1 + value = sortValue $ gst <> minAda + in mconcat + [ input $ + script govValidatorHash + . withValue value + . withOutRef governorRef + . withDatum governorInputDatum + , output $ + script govValidatorHash + . withValue value + . withOutRef governorRef + . withDatum (mkGovernorOutputDatum ps) + ] + +{- | The proposal redeemer used to spend the governor UTXO, which is always + 'MintGATs' in this case. +-} +governorRedeemer :: GovernorRedeemer +governorRedeemer = MintGATs + +-------------------------------------------------------------------------------- + +-- * Authority Token + +{- | Create a context builder that contains the infomation about the minted + authority tokens and where they're sent to. +-} +mkAuthorityTokenBuilder :: + forall b. + CombinableBuilder b => + AuthorityTokenParameters -> + b +mkAuthorityTokenBuilder (AuthorityTokenParameters es mdt invalidTokenName) = + foldMap perEffect es + where + perEffect :: ValidatorHash -> b + perEffect vh = + let tn = + if invalidTokenName + then "" + else validatorHashToTokenName vh + ac = AssetClass (authorityTokenSymbol, tn) + minted = Value.assetClassValue ac 1 + value = sortValue $ minAda <> minted + in mconcat + [ mint minted + , output $ + script vh + . maybe id withDatum mdt + . withValue value + ] + +-- | The redeemer used while running the authority token policy. +authorityTokenRedeemer :: () +authorityTokenRedeemer = () + +-------------------------------------------------------------------------------- -- | Create a 'TxInfo' that update the status of a proposal. advance :: - Parameters -> - TxInfo -advance ps = - let pst = Value.singleton proposalPolicySymbol "" 1 - sst = Value.assetClassValue stakeAssetClass 1 + forall b. + CombinableBuilder b => + ParameterBundle -> + b +advance pb = + let mkBuilderMaybe = maybe mempty + in mconcat + [ mkProposalBuilder pb.proposalParameters + , mkStakeBuilder pb.stakeParameters + , mkBuilderMaybe mkGovernorBuilder pb.governorParameters + , mkBuilderMaybe mkAuthorityTokenBuilder pb.authorityTokenParameters + , timeRange pb.transactionTimeRange + , maybe mempty signedWith pb.extraSignature + ] - proposalInputDatum :: ProposalDatum - proposalInputDatum = - mkProposalInputDatum ps +-------------------------------------------------------------------------------- - proposalOutputDatum :: ProposalDatum - proposalOutputDatum = - proposalInputDatum - { status = ps.toStatus - } +{- | Create a test tree that runs the relavant componets to test the advancing + functionalities. +-} +mkTestTree :: + String -> + ParameterBundle -> + Validity -> + SpecificationTree +mkTestTree name pb val = + group name $ catMaybes [proposal, stake, governor, authority] + where + spend = mkSpending advance pb + mint = mkMinting advance pb - stakeInputDatums :: [StakeDatum] - stakeInputDatums = mkStakeInputDatums ps + proposal = + let proposalInputDatum = mkProposalInputDatum pb.proposalParameters + in Just $ + testValidator + val.forProposalValidator + "proposal" + (proposalValidator Shared.proposal) + proposalInputDatum + proposalRedeemer + (spend proposalRef) - mkStakeOutputDatum :: StakeDatum -> StakeDatum - mkStakeOutputDatum si = - if ps.alterOutputStakes - then - si - { stakedAmount = ps.perStakeGTs + 1 - } - else si + stake = + let idx = 0 + in Just $ + testValidator + val.forStakeValidator + "stake" + (stakeValidator Shared.stake) + (getStakeInputDatumAt pb.stakeParameters idx) + stakeRedeemer + ( spend (mkStakeRef idx) + ) - stakeValue = - let gts = - if ps.perStakeGTs == 0 - then mempty - else - Value.assetClassValue - (untag stake.gtClassRef) - (untag ps.perStakeGTs) - in sortValue $ - sst <> minAda - <> gts + governor = + testValidator + (fromJust val.forGovernorValidator) + "governor" + (governorValidator Shared.governor) + governorInputDatum + governorRedeemer + (spend governorRef) + <$ pb.governorParameters - stakeBuilder :: BaseBuilder - stakeBuilder = - foldMap - ( \(si, idx) -> - let so = mkStakeOutputDatum si - in mconcat @BaseBuilder - [ input $ - script stakeValidatorHash - . withValue stakeValue - . withDatum si - . withOutRef (mkStakeRef idx) - , output $ - script stakeValidatorHash - . withValue stakeValue - . withDatum so - ] - ) - $ let withIds = zip stakeInputDatums [0 ..] - in if ps.includeAllStakes - then withIds - else [head withIds] + authority = + testPolicy + (fromJust val.forAuthorityTokenPolicy) + "authority" + (authorityTokenPolicy $ AuthorityToken Shared.govAssetClass) + authorityTokenRedeemer + (mint authorityTokenSymbol) + <$ (pb.authorityTokenParameters) - signBuilder :: BaseBuilder - signBuilder = - let sos = mkStakeOwners ps - in if ps.signByAllCosigners - then foldMap signedWith sos - else signedWith $ head sos +{- | Create a test tree that runs a bunch of parameter bundles. These bundles + should have the same validity. +-} +mkTestTree' :: + String -> + (ParameterBundle -> String) -> + [ParameterBundle] -> + Validity -> + SpecificationTree +mkTestTree' groupName mkCaseName bundles val = + group groupName $ + (\b -> mkTestTree (mkCaseName b) b val) + <$> bundles - builder :: BaseBuilder - builder = - mconcat - [ txId "95ba4015e30aef16a3461ea97a779f814aeea6b8009d99a94add4b8293be737a" - , signBuilder - , timeRange ps.validTimeRange - , input $ - script proposalValidatorHash - . withValue pst - . withDatum proposalInputDatum - . withTxId proposalTxRef - , output $ - script proposalValidatorHash - . withValue (pst <> minAda) - . withDatum proposalOutputDatum - ] - in buildTxInfoUnsafe $ builder <> stakeBuilder +-------------------------------------------------------------------------------- ---- +-- Utilities for creating parameter bundles {- | Given the proposal status, create a time range that is in time for advacing to the next state. @@ -394,8 +695,6 @@ mkTooLateTimeRange advanceFrom = ) Finished -> error "Cannot advance 'Finished' proposal" ---- - -- | Next state of the given proposal status. getNextState :: ProposalStatus -> ProposalStatus getNextState = \case @@ -404,143 +703,372 @@ getNextState = \case Locked -> Finished Finished -> error "Cannot advance 'Finished' proposal" +-- | Calculate the number of GTs per stake in order to exceed the minimum limit. +compPerStakeGTsForDraft :: NumStake -> Integer +compPerStakeGTsForDraft nCosigners = + untag (def :: ProposalThresholds).vote + `div` fromIntegral nCosigners + 1 + +dummyDatum :: () +dummyDatum = () + +dummyDatumHash :: DatumHash +dummyDatumHash = datumHash $ toDatum dummyDatum + +-- | Create given number of effect groups. Each group will have 3 effects. +mkMockEffects :: Int -> [AssocMap.Map ValidatorHash DatumHash] +mkMockEffects = + flip + take + ( AssocMap.fromList + . flip zip (repeat dummyDatumHash) + <$> groupsOfN 3 validatorHashes + ) + +numberOfVotesThatExceedsTheMinimumRequirement :: Integer +numberOfVotesThatExceedsTheMinimumRequirement = + untag (def @ProposalThresholds).execute + 1 + +mkWinnerVotes :: Index -> (Winner, Integer) +mkWinnerVotes idx = + ( EffectAt idx + , numberOfVotesThatExceedsTheMinimumRequirement + ) + +ambiguousWinnerVotes :: (Winner, Integer) +ambiguousWinnerVotes = + ( All + , numberOfVotesThatExceedsTheMinimumRequirement + ) + +-------------------------------------------------------------------------------- + +-- * Parameter Bundles + --- -advanceToNextStateInTimeParameters :: Int -> [Parameters] -advanceToNextStateInTimeParameters nCosigners = - map - ( \from -> - let -- Set the vote count of outcome 0 to @def.countingVoting + 1@, - -- meaning that outcome 0 will be the winner. - outcome0WinningVotes = - ProposalVotes $ - updateMap - (\_ -> Just $ untag (def :: ProposalThresholds).execute + 1) - (ResultTag 0) - (coerce emptyVotes) +-- * Legal - votes = case from of - Draft -> emptyVotes - -- With sufficient votes - _ -> outcome0WinningVotes +defaultWinnerIdx :: Index +defaultWinnerIdx = 0 - includeAllStakes = case from of - Draft -> True - _ -> False +{- | Advance a proposal to the next state, perfectly valid for all the + componets. +-} +mkValidToNextStateBundle :: + -- | Number of cosigners. + Word -> + -- | Number of effects + Word -> + -- | The initial proposal state, should not be 'Finished'. + ProposalStatus -> + ParameterBundle +mkValidToNextStateBundle _ _ Finished = + error "Cannot advance from Finished" +mkValidToNextStateBundle nCosigners nEffects from = + let next = getNextState from + effects = mkMockEffects $ fromIntegral nEffects + winner = defaultWinnerIdx - signByAllCosigners = case from of - Draft -> True - _ -> False - in Parameters - { fromStatus = from - , toStatus = getNextState from - , votes = votes - , includeAllStakes = includeAllStakes - , validTimeRange = mkInTimeTimeRange from - , alterOutputStakes = False - , stakeCount = fromIntegral nCosigners - , signByAllCosigners = signByAllCosigners - , perStakeGTs = - (def :: ProposalThresholds).vote - `div` fromIntegral nCosigners + 1 - } - ) - [Draft, VotingReady, Locked] - -advanceToFailedStateDueToTimeoutParameters :: Int -> [Parameters] -advanceToFailedStateDueToTimeoutParameters nCosigners = - map - ( \from -> - Parameters - { fromStatus = from - , toStatus = Finished - , votes = emptyVotes - , includeAllStakes = False - , validTimeRange = mkTooLateTimeRange from - , alterOutputStakes = False - , stakeCount = fromIntegral nCosigners - , signByAllCosigners = False - , perStakeGTs = 1 + template = + ParameterBundle + { proposalParameters = + ProposalParameters + { fromStatus = from + , toStatus = next + , effectList = effects + , winnerAndVotes = Nothing + , numCosigners = fromIntegral nCosigners + , invalidProposalOutputDatum = False + } + , stakeParameters = + StakeParameters + { numStake = 1 + , perStakeGTs = + compPerStakeGTsForDraft $ + fromIntegral nCosigners + , transactionSignedByOwners = False + , invalidStakeOutputDatum = False + } + , governorParameters = Nothing + , authorityTokenParameters = Nothing + , transactionTimeRange = mkInTimeTimeRange from + , extraSignature = Just signer } - ) - [Draft, VotingReady, Locked] -insufficientVotesParameters :: Parameters -insufficientVotesParameters = - let votes = emptyVotes - from = VotingReady - to = getNextState from - in Parameters - { fromStatus = from - , toStatus = to - , votes = votes - , includeAllStakes = False - , validTimeRange = mkInTimeTimeRange from - , alterOutputStakes = False - , stakeCount = 1 - , signByAllCosigners = True - , perStakeGTs = 20 - } + -- This is my favourite part of the test suite, lol. + modifyTemplate = do + when (from == Draft) $ + modify $ \b -> + b + { stakeParameters = + b.stakeParameters + { transactionSignedByOwners = True + , numStake = fromIntegral nCosigners + } + , extraSignature = Nothing + } -insufficientCosignsParameters :: Int -> Parameters -insufficientCosignsParameters nCosigners = - (\ps -> ps {perStakeGTs = 0}) $ - head $ - advanceToNextStateInTimeParameters nCosigners + when (from == VotingReady || from == Locked) $ + modify $ \b -> + b + { proposalParameters = + b.proposalParameters + { winnerAndVotes = Just $ mkWinnerVotes winner + } + } -advanceFromFinishedParameters :: Parameters -advanceFromFinishedParameters = - Parameters - { fromStatus = Finished - , toStatus = Finished - , votes = emptyVotes - , includeAllStakes = False - , validTimeRange = always - , alterOutputStakes = False - , stakeCount = 1 - , signByAllCosigners = True - , perStakeGTs = 20 + when (from == Locked) $ + modify $ \b -> + let aut = + AuthorityTokenParameters + { mintGATsFor = AssocMap.keys $ effects !! winner + , carryDatum = Just dummyDatum + , invalidTokenName = False + } + gov = + GovernorParameters + { invalidGovernorOutputDatum = False + } + in b + { governorParameters = Just gov + , authorityTokenParameters = Just aut + } + in execState modifyTemplate template + +mkValidToNextStateBundles :: + -- | Number of cosigners + Word -> + -- | Number of effects + Word -> + [ParameterBundle] +mkValidToNextStateBundles nCosigners nEffects = + mkValidToNextStateBundle nCosigners nEffects + <$> [ Draft + , VotingReady + , Locked + ] + +mkValidToFailedStateBundles :: + -- | Number of cosigners + Word -> + -- | Number of effects + Word -> + [ParameterBundle] +mkValidToFailedStateBundles nCosigners nEffects = + mkBundle + <$> [ Draft + , VotingReady + , Locked + ] + where + mkBundle from = + let next = Finished + effects = mkMockEffects $ fromIntegral nEffects + in ParameterBundle + { proposalParameters = + ProposalParameters + { fromStatus = from + , toStatus = next + , effectList = effects + , winnerAndVotes = Nothing + , numCosigners = fromIntegral nCosigners + , invalidProposalOutputDatum = False + } + , stakeParameters = + StakeParameters + { numStake = 1 + , perStakeGTs = + compPerStakeGTsForDraft $ + fromIntegral nCosigners + , transactionSignedByOwners = False + , invalidStakeOutputDatum = False + } + , governorParameters = Nothing + , authorityTokenParameters = Nothing + , transactionTimeRange = mkTooLateTimeRange from + , extraSignature = Just signer + } + +-- * Illegal + +mkFromFinishedBundles :: + -- | Number of cosigners + Word -> + -- | Number of effects + Word -> + [ParameterBundle] +mkFromFinishedBundles nCosigners nEffects = + mkBundle + <$> [ Draft + , VotingReady + , Locked + ] + where + mkBundle from = + let template = mkValidToNextStateBundle nCosigners nEffects from + in template + { proposalParameters = + template.proposalParameters + { fromStatus = Finished + , toStatus = Finished + } + } + +mkToNextStateTooLateBundles :: Word -> Word -> [ParameterBundle] +mkToNextStateTooLateBundles nCosigners nEffects = + mkBundle + <$> [ Draft + , VotingReady + , Locked + ] + where + mkBundle from = + let template = mkValidToNextStateBundle nCosigners nEffects from + in template + { transactionTimeRange = mkTooLateTimeRange from + } + +mkInvalidOutputStakeBundles :: Word -> Word -> [ParameterBundle] +mkInvalidOutputStakeBundles nCosigners nEffects = + mkBundle <$> [Draft, VotingReady, Locked] + where + mkBundle from = + let template = mkValidToNextStateBundle nCosigners nEffects from + in template + { stakeParameters = + template.stakeParameters + { invalidStakeOutputDatum = True + } + } + +-- * From Draft + +mkInsufficientCosignsBundle :: Word -> Word -> ParameterBundle +mkInsufficientCosignsBundle nCosigners nEffects = + template + { stakeParameters = + template.stakeParameters + { perStakeGTs = insuffcientPerStakeGTs + } + } + where + insuffcientPerStakeGTs = + untag (def :: ProposalThresholds).vote + `div` fromIntegral nCosigners - 1 + template = mkValidToNextStateBundle nCosigners nEffects Draft + +-- * From VotingReady + +setWinnerAndVotes :: + ParameterBundle -> + Maybe (Winner, Integer) -> + ParameterBundle +setWinnerAndVotes pb wv = + pb + { proposalParameters = + pb.proposalParameters + { winnerAndVotes = wv + } } -invalidOutputStakeParameters :: Int -> [Parameters] -invalidOutputStakeParameters nCosigners = - (\ps -> ps {alterOutputStakes = True}) - <$> advanceToNextStateInTimeParameters nCosigners +mkInsufficientVotesBundle :: + Word -> + Word -> + ParameterBundle +mkInsufficientVotesBundle nCosigners nEffects = + mkValidToNextStateBundle nCosigners nEffects VotingReady + `setWinnerAndVotes` Nothing ---- +mkAmbiguousWinnerBundle :: + Word -> + Word -> + ParameterBundle +mkAmbiguousWinnerBundle nCosigners nEffects = + mkValidToNextStateBundle nCosigners nEffects VotingReady + `setWinnerAndVotes` Just ambiguousWinnerVotes -{- | 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] +-- * From Locked + +mkValidFromLockedBundle :: Word -> Word -> ParameterBundle +mkValidFromLockedBundle nCosigners nEffects = + mkValidToNextStateBundle nCosigners nEffects Locked + +mkMintGATsForWrongEffectsBundle :: + Word -> + Word -> + ParameterBundle +mkMintGATsForWrongEffectsBundle nCosigners nEffects = + template + { authorityTokenParameters = + ( \aut -> + aut + { mintGATsFor = + [ validatorHashes !! 1 + , validatorHashes !! 3 + , validatorHashes !! 5 + , validatorHashes !! 7 + ] + } + ) + <$> template.authorityTokenParameters + } where - txInfo = advance ps + template = mkValidFromLockedBundle nCosigners nEffects - proposal = - let proposalInputDatum = mkProposalInputDatum ps - in testValidator - isValidForProposalValidator - "propsoal" - (proposalValidator Shared.proposal) - proposalInputDatum - proposalRedeemer - ( ScriptContext - txInfo - proposalScriptPurpose - ) +mkNoGATMintedBundle :: + Word -> + Word -> + ParameterBundle +mkNoGATMintedBundle nCosigners nEffects = + template + { authorityTokenParameters = Nothing + } + where + template = mkValidFromLockedBundle nCosigners nEffects - stake = - let idx = 0 - stakeInputDatum = mkStakeInputDatums ps !! idx - isValid = not $ ps.alterOutputStakes - in testValidator - isValid - "stake" - (stakeValidator Shared.stake) - stakeInputDatum - stakeRedeemer - ( ScriptContext - txInfo - (mkStakeScriptPurpose idx) - ) +mkMintGATsWithoutTagBundle :: + Word -> + Word -> + ParameterBundle +mkMintGATsWithoutTagBundle nCosigners nEffects = + template + { authorityTokenParameters = + ( \aut -> + aut + { invalidTokenName = True + } + ) + <$> template.authorityTokenParameters + } + where + template = mkValidFromLockedBundle nCosigners nEffects + +mkGATsWithWrongDatumBundle :: + Word -> + Word -> + ParameterBundle +mkGATsWithWrongDatumBundle nCosigners nEffects = + template + { authorityTokenParameters = Just newAut + } + where + template = mkValidFromLockedBundle nCosigners nEffects + aut = fromJust template.authorityTokenParameters + newAut = + AuthorityTokenParameters + aut.mintGATsFor + (Just (1 :: Integer)) + False + +mkBadGovernorOutputDatumBundle :: + Word -> + Word -> + ParameterBundle +mkBadGovernorOutputDatumBundle nCosigners nEffects = + template + { governorParameters = Just gov + } + where + template = mkValidFromLockedBundle nCosigners nEffects + gov = GovernorParameters True diff --git a/agora-specs/Sample/Proposal/Cosign.hs b/agora-specs/Sample/Proposal/Cosign.hs index f9a3865..4922c04 100644 --- a/agora-specs/Sample/Proposal/Cosign.hs +++ b/agora-specs/Sample/Proposal/Cosign.hs @@ -40,8 +40,6 @@ import Data.Default (def) import Data.List (sort) import Data.Tagged (Tagged, untag) import Plutarch.Context ( - BaseBuilder, - buildTxInfoUnsafe, input, output, script, @@ -49,16 +47,13 @@ import Plutarch.Context ( timeRange, txId, withDatum, - withRefIndex, + withOutRef, withTxId, withValue, ) import PlutusLedgerApi.V1 ( POSIXTimeRange, PubKeyHash, - ScriptContext (ScriptContext), - ScriptPurpose (Spending), - TxInfo, TxOutRef (..), Value, ) @@ -80,7 +75,7 @@ import Test.Specification ( group, testValidator, ) -import Test.Util (closedBoundedInterval, pubKeyHashes, sortValue) +import Test.Util (CombinableBuilder, closedBoundedInterval, mkSpending, pubKeyHashes, sortValue) -- | Parameters for cosigning a proposal. data Parameters = Parameters @@ -138,8 +133,8 @@ mkStakeInputDatums :: Parameters -> [StakeDatum] mkStakeInputDatums = fmap (\pk -> StakeDatum perStakedGTs pk []) . newCosigners -- | Create a 'TxInfo' that tries to cosign a proposal with new cosigners. -cosign :: Parameters -> TxInfo -cosign ps = buildTxInfoUnsafe builder +cosign :: forall b. CombinableBuilder b => Parameters -> b +cosign ps = builder where pst = Value.singleton proposalPolicySymbol "" 1 sst = Value.assetClassValue stakeAssetClass 1 @@ -158,7 +153,6 @@ cosign ps = buildTxInfoUnsafe builder (untag perStakedGTs) <> sst - stakeBuilder :: BaseBuilder stakeBuilder = foldMap ( \(stakeDatum, refIdx) -> @@ -166,13 +160,13 @@ cosign ps = buildTxInfoUnsafe builder if ps.alterOutputStakes then stakeDatum {stakedAmount = 0} else stakeDatum - in mconcat @BaseBuilder + in mconcat [ input $ script stakeValidatorHash . withValue stakeValue . withDatum stakeDatum . withTxId stakeTxRef - . withRefIndex refIdx + . withOutRef (mkStakeRef refIdx) , output $ script stakeValidatorHash . withValue stakeValue @@ -182,7 +176,7 @@ cosign ps = buildTxInfoUnsafe builder ) $ zip stakeInputDatums - [2 ..] + [0 ..] --- @@ -192,7 +186,6 @@ cosign ps = buildTxInfoUnsafe builder proposalOutputDatum :: ProposalDatum proposalOutputDatum = mkProposalOutputDatum ps - proposalBuilder :: BaseBuilder proposalBuilder = mconcat [ input $ @@ -200,7 +193,7 @@ cosign ps = buildTxInfoUnsafe builder . withValue pst . withDatum proposalInputDatum . withTxId proposalTxRef - . withRefIndex proposalRefIdx + . withOutRef proposalRef , output $ script proposalValidatorHash . withValue (sortValue (pst <> minAda)) @@ -217,7 +210,6 @@ cosign ps = buildTxInfoUnsafe builder --- - builder :: BaseBuilder builder = mconcat [ txId "05c67819fc3381a2052b929ab439244b7b5fe3b3bd07f2134055bbbb21bd9e52" @@ -231,21 +223,15 @@ proposalRefIdx :: Integer proposalRefIdx = 1 -- | Spend the proposal ST. -proposalScriptPurpose :: ScriptPurpose -proposalScriptPurpose = - Spending - ( TxOutRef - proposalTxRef - proposalRefIdx - ) +proposalRef :: TxOutRef +proposalRef = TxOutRef proposalTxRef proposalRefIdx -- | Consume the given stake. -mkStakeScriptPurpose :: Int -> ScriptPurpose -mkStakeScriptPurpose idx = - Spending $ - TxOutRef - stakeTxRef - $ proposalRefIdx + 1 + fromIntegral idx +mkStakeRef :: Int -> TxOutRef +mkStakeRef idx = + TxOutRef + stakeTxRef + $ proposalRefIdx + 1 + fromIntegral idx -- | Create a proposal redeemer which cosigns with the new cosginers. mkProposalRedeemer :: Parameters -> ProposalRedeemer @@ -321,20 +307,17 @@ mkTestTree :: SpecificationTree mkTestTree name ps isValid = group name [proposal, stake] where - txInfo = cosign ps + spend = mkSpending cosign ps proposal = let proposalInputDatum = mkProposalInputDatum ps in testValidator isValid - "propsoal" + "proposal" (proposalValidator Shared.proposal) proposalInputDatum (mkProposalRedeemer ps) - ( ScriptContext - txInfo - proposalScriptPurpose - ) + (spend proposalRef) stake = let idx = 0 @@ -346,7 +329,4 @@ mkTestTree name ps isValid = group name [proposal, stake] (stakeValidator Shared.stake) stakeInputDatum stakeRedeemer - ( ScriptContext - txInfo - (mkStakeScriptPurpose idx) - ) + (spend $ mkStakeRef idx) diff --git a/agora-specs/Sample/Proposal/Create.hs b/agora-specs/Sample/Proposal/Create.hs index 3556256..6ec1fac 100644 --- a/agora-specs/Sample/Proposal/Create.hs +++ b/agora-specs/Sample/Proposal/Create.hs @@ -45,8 +45,6 @@ import Data.Coerce (coerce) import Data.Default (Default (def)) import Data.Tagged (Tagged, untag) import Plutarch.Context ( - BaseBuilder, - buildTxInfoUnsafe, input, mint, output, @@ -63,9 +61,6 @@ import PlutusLedgerApi.V1 ( POSIXTime (POSIXTime), POSIXTimeRange, PubKeyHash, - ScriptContext (ScriptContext), - ScriptPurpose (Minting, Spending), - TxInfo, TxOutRef (TxOutRef), ValidatorHash, always, @@ -88,7 +83,7 @@ import Sample.Shared ( ) import Sample.Shared qualified as Shared import Test.Specification (SpecificationTree, group, testPolicy, testValidator) -import Test.Util (closedBoundedInterval, sortValue) +import Test.Util (CombinableBuilder, closedBoundedInterval, mkMinting, mkSpending, sortValue) -- | Parameters for creating a proposal. data Parameters = Parameters @@ -242,7 +237,7 @@ mkTimeRange ps = in closedBoundedInterval s $ o + di else always --- | Get the starting time of the propsoal. +-- | Get the starting time of the proposal. mkProposalStartingTime :: Parameters -> ProposalStartingTime mkProposalStartingTime ps = if ps.timeRangeClosed @@ -269,8 +264,8 @@ governorRef = TxOutRef "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be -------------------------------------------------------------------------------- -- | Create a 'TxInfo' that spends a stake to create a new proposal. -createProposal :: Parameters -> TxInfo -createProposal ps = buildTxInfoUnsafe builder +createProposal :: forall b. CombinableBuilder b => Parameters -> b +createProposal ps = builder where pst = Value.singleton proposalPolicySymbol "" 1 sst = Value.assetClassValue stakeAssetClass 1 @@ -296,7 +291,6 @@ createProposal ps = buildTxInfoUnsafe builder --- - builder :: BaseBuilder builder = mconcat [ txId "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be" @@ -413,7 +407,7 @@ invalidProposalStatusParameters = -------------------------------------------------------------------------------- -{- | Create a test tree that runs the propsoal minting policy, the governor +{- | Create a test tree that runs the proposal minting policy, the governor validator and the stake validator to test the functionalities of creting proposals -} @@ -426,7 +420,8 @@ mkTestTree validForStakeValidator = group name [proposalTest, governorTest, stakeTest] where - txInfo = createProposal ps + mint = mkMinting createProposal ps + spend = mkSpending createProposal ps proposalTest = testPolicy @@ -434,7 +429,7 @@ mkTestTree "proposal" (proposalPolicy Shared.proposal.governorSTAssetClass) proposalPolicyRedeemer - (ScriptContext txInfo (Minting proposalPolicySymbol)) + (mint proposalPolicySymbol) governorTest = testValidator @@ -443,11 +438,7 @@ mkTestTree (governorValidator Shared.governor) governorInputDatum governorRedeemer - ( ScriptContext - txInfo - (Spending governorRef) - ) - + (spend governorRef) stakeTest = testValidator validForStakeValidator @@ -455,7 +446,4 @@ mkTestTree (stakeValidator Shared.stake) (mkStakeInputDatum ps) stakeRedeemer - ( ScriptContext - txInfo - (Spending stakeRef) - ) + (spend stakeRef) diff --git a/agora-specs/Sample/Proposal/Shared.hs b/agora-specs/Sample/Proposal/Shared.hs index 0082f68..c73f1c9 100644 --- a/agora-specs/Sample/Proposal/Shared.hs +++ b/agora-specs/Sample/Proposal/Shared.hs @@ -1,18 +1,21 @@ {- | Module : Sample.Proposal.Shared Maintainer : connor@mlabs.city -Description: Shared constants for propsoal samples +Description: Shared constants for proposal samples -Shared constants for propsoal samples. +Shared constants for proposal samples. -} -module Sample.Proposal.Shared (proposalTxRef, stakeTxRef) where +module Sample.Proposal.Shared (proposalTxRef, stakeTxRef, governorTxRef) where import PlutusLedgerApi.V1 (TxId) --- | 'TxId' of all the propsoal inputs in the samples. +-- | 'TxId' of all the proposal inputs in the samples. proposalTxRef :: TxId proposalTxRef = "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be" -- | 'TxId' of all the stake inputs in the samples. stakeTxRef :: TxId stakeTxRef = "0ca36f3a357bc69579ab2531aecd1e7d3714d993c7820f40b864be15" + +governorTxRef :: TxId +governorTxRef = "cb076140e80d240f9c89e478aedbddbe6f4734fecbd0ae3e37404c12e7798c0f" diff --git a/agora-specs/Sample/Proposal/UnlockStake.hs b/agora-specs/Sample/Proposal/UnlockStake.hs index 20b1be5..e5b47d6 100644 --- a/agora-specs/Sample/Proposal/UnlockStake.hs +++ b/agora-specs/Sample/Proposal/UnlockStake.hs @@ -40,8 +40,6 @@ import Agora.Stake.Scripts (stakeValidator) import Data.Default.Class (Default (def)) import Data.Tagged (Tagged (..), untag) import Plutarch.Context ( - BaseBuilder, - buildTxInfoUnsafe, input, output, script, @@ -54,9 +52,6 @@ import Plutarch.Context ( import PlutusLedgerApi.V1 ( DatumHash, PubKeyHash, - ScriptContext (..), - ScriptPurpose (Spending), - TxInfo (..), TxOutRef (..), ValidatorHash, ) @@ -74,7 +69,7 @@ import Sample.Shared ( ) import Sample.Shared qualified as Shared import Test.Specification (SpecificationTree, group, testValidator) -import Test.Util (sortValue, updateMap) +import Test.Util (CombinableBuilder, mkSpending, sortValue, updateMap) -------------------------------------------------------------------------------- @@ -249,7 +244,7 @@ mkProposalDatumPair params pid = getProposalVotes votesTemplate -- | Create a 'TxInfo' that tries to unlock a stake. -unlockStake :: Parameters -> TxInfo +unlockStake :: forall b. CombinableBuilder b => Parameters -> b unlockStake ps = let pst = Value.singleton proposalPolicySymbol "" 1 sst = Value.assetClassValue stakeAssetClass 1 @@ -260,7 +255,6 @@ unlockStake ps = foldMap ( \((i, o), idx) -> mconcat - @BaseBuilder [ input $ script proposalValidatorHash . withValue pst @@ -288,7 +282,7 @@ unlockStake ps = sOutDatum = mkStakeOutputDatum ps stakes = - mconcat @BaseBuilder + mconcat [ input $ script stakeValidatorHash . withValue stakeValue @@ -301,13 +295,13 @@ unlockStake ps = ] builder = - mconcat @BaseBuilder + mconcat [ txId "388bc0b897b3dadcd479da4c88291de4113a50b72ddbed001faf7fc03f11bc52" , proposals , stakes , signedWith defOwner ] - in buildTxInfoUnsafe builder + in builder -- | Reference to the stake UTXO. stakeRef :: TxOutRef @@ -523,7 +517,7 @@ mkAlterStakeParameters nProposals = do mkTestTree :: String -> Parameters -> Bool -> SpecificationTree mkTestTree name ps isValid = group name [stake, proposal] where - txInfo = unlockStake ps + spend = mkSpending unlockStake ps stake = testValidator @@ -532,7 +526,7 @@ mkTestTree name ps isValid = group name [stake, proposal] (stakeValidator Shared.stake) (mkStakeInputDatum ps) stakeRedeemer - (ScriptContext txInfo (Spending stakeRef)) + (spend stakeRef) proposal = let idx = 0 @@ -540,8 +534,8 @@ mkTestTree name ps isValid = group name [stake, proposal] ref = mkProposalRef idx in testValidator isValid - "propsoal" + "proposal" (proposalValidator Shared.proposal) (mkProposalInputDatum ps pid) proposalRedeemer - (ScriptContext txInfo (Spending ref)) + (spend ref) diff --git a/agora-specs/Sample/Proposal/Vote.hs b/agora-specs/Sample/Proposal/Vote.hs index 36ed93d..765cd82 100644 --- a/agora-specs/Sample/Proposal/Vote.hs +++ b/agora-specs/Sample/Proposal/Vote.hs @@ -33,8 +33,6 @@ import Agora.Stake.Scripts (stakeValidator) import Data.Default (Default (def)) import Data.Tagged (Tagged (Tagged), untag) import Plutarch.Context ( - BaseBuilder, - buildTxInfoUnsafe, input, output, script, @@ -47,9 +45,6 @@ import Plutarch.Context ( ) import PlutusLedgerApi.V1 ( PubKeyHash, - ScriptContext (..), - ScriptPurpose (Spending), - TxInfo, TxOutRef (TxOutRef), ) import PlutusLedgerApi.V1.Value qualified as Value @@ -71,7 +66,7 @@ import Test.Specification ( testValidator, validatorSucceedsWith, ) -import Test.Util (closedBoundedInterval, sortValue, updateMap) +import Test.Util (CombinableBuilder, closedBoundedInterval, mkSpending, sortValue, updateMap) -- | Reference to the proposal UTXO. proposalRef :: TxOutRef @@ -152,7 +147,7 @@ stakeRedeemer :: StakeRedeemer stakeRedeemer = PermitVote -- | Create a valid transaction that votes on a propsal, given the parameters. -vote :: Parameters -> TxInfo +vote :: forall b. CombinableBuilder b => Parameters -> b vote params = let pst = Value.singleton proposalPolicySymbol "" 1 sst = Value.assetClassValue stakeAssetClass 1 @@ -203,7 +198,6 @@ vote params = <> Value.assetClassValue (untag stake.gtClassRef) params.voteCount <> minAda - builder :: BaseBuilder builder = mconcat [ txId "827598fb2d69a896bbd9e645bb14c307df907f422b39eecbe4d6329bc30b428c" @@ -228,7 +222,7 @@ vote params = . withValue stakeValue . withDatum stakeOutputDatum ] - in buildTxInfoUnsafe builder + in builder --- @@ -248,19 +242,16 @@ validVoteParameters = mkTestTree :: String -> Parameters -> Bool -> SpecificationTree mkTestTree name ps isValid = group name [proposal, stake] where - txInfo = vote ps + spend = mkSpending vote ps proposal = testValidator isValid - "propsoal" + "proposal" (proposalValidator Shared.proposal) proposalInputDatum (mkProposalRedeemer ps) - ( ScriptContext - txInfo - (Spending proposalRef) - ) + (spend proposalRef) stake = let stakeInputDatum = mkStakeInputDatum ps @@ -269,7 +260,4 @@ mkTestTree name ps isValid = group name [proposal, stake] (stakeValidator Shared.stake) stakeInputDatum stakeRedeemer - ( ScriptContext - txInfo - (Spending stakeRef) - ) + (spend stakeRef) diff --git a/agora-specs/Sample/Shared.hs b/agora-specs/Sample/Shared.hs index c1197e3..8e6c476 100644 --- a/agora-specs/Sample/Shared.hs +++ b/agora-specs/Sample/Shared.hs @@ -138,7 +138,7 @@ governor = Governor oref gt mc Value.assetClass "da8c30857834c6ae7203935b89278c532b3995245295456f993e1d24" "LQ" - mc = 6 + mc = 20 govPolicy :: MintingPolicy govPolicy = mkMintingPolicy (governorPolicy governor) @@ -186,7 +186,7 @@ instance Default ProposalThresholds where ProposalThresholds { execute = Tagged 1000 , create = Tagged 1 - , vote = Tagged 10 + , vote = Tagged 100 } authorityToken :: AuthorityToken diff --git a/agora-specs/Sample/Stake.hs b/agora-specs/Sample/Stake.hs index 88e5dc7..ba1a835 100644 --- a/agora-specs/Sample/Stake.hs +++ b/agora-specs/Sample/Stake.hs @@ -40,8 +40,9 @@ import Plutarch.Context ( signedWith, txId, withDatum, - withSpending, - withTxId, + withMinting, + withOutRef, + withSpendingOutRef, withValue, ) import PlutusLedgerApi.V1 ( @@ -53,6 +54,7 @@ import PlutusLedgerApi.V1 ( TxInfo (txInfoData, txInfoSignatories), ValidatorHash (ValidatorHash), ) +import PlutusLedgerApi.V1.Contexts (TxOutRef (..)) import PlutusLedgerApi.V1.Value qualified as Value ( assetClassValue, singleton, @@ -86,6 +88,7 @@ stakeCreation = script stakeValidatorHash . withValue (st <> Value.singleton "da8c30857834c6ae7203935b89278c532b3995245295456f993e1d24" "LQ" 424242424242) . withDatum datum + , withMinting stakeSymbol ] in buildMintingUnsafe builder @@ -130,6 +133,9 @@ stakeDepositWithdraw config = stakeAfter :: StakeDatum stakeAfter = stakeBefore {stakedAmount = stakeBefore.stakedAmount + config.delta} + stakeRef :: TxOutRef + stakeRef = TxOutRef "0ffef57e30cc604342c738e31e0451593837b313e7bfb94b0922b142782f98e6" 1 + builder :: SpendingBuilder builder = mconcat @@ -140,14 +146,11 @@ stakeDepositWithdraw config = script stakeValidatorHash . withValue (st <> Value.assetClassValue (untag stake.gtClassRef) (untag stakeBefore.stakedAmount)) . withDatum stakeAfter - . withTxId "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be" + . withOutRef stakeRef , output $ script stakeValidatorHash . withValue (st <> Value.assetClassValue (untag stake.gtClassRef) (untag stakeAfter.stakedAmount)) . withDatum stakeAfter - , withSpending $ - script stakeValidatorHash - . withValue (st <> Value.assetClassValue (untag stake.gtClassRef) (untag stakeBefore.stakedAmount)) - . withDatum stakeAfter + , withSpendingOutRef stakeRef ] in buildSpendingUnsafe builder diff --git a/agora-specs/Sample/Treasury.hs b/agora-specs/Sample/Treasury.hs index 632f559..2c3c902 100644 --- a/agora-specs/Sample/Treasury.hs +++ b/agora-specs/Sample/Treasury.hs @@ -28,6 +28,7 @@ import Plutarch.Context ( script, signedWith, txId, + withMinting, withTxId, withValue, ) @@ -67,6 +68,7 @@ baseCtxBuilder = , mint (Value.singleton gatCs gatTn (-1)) , input treasury , output treasury + , withMinting gatCs ] {- | A `ScriptContext` that should be compatible with treasury diff --git a/agora-specs/Spec/AuthorityToken.hs b/agora-specs/Spec/AuthorityToken.hs index 46b7423..93d7bea 100644 --- a/agora-specs/Spec/AuthorityToken.hs +++ b/agora-specs/Spec/AuthorityToken.hs @@ -11,19 +11,18 @@ module Spec.AuthorityToken (specs) where import Agora.AuthorityToken (singleAuthorityTokenBurned) import Plutarch (ClosedTerm, POpaque, compile, perror, popaque) +import Plutarch.Unsafe (punsafeCoerce) import PlutusLedgerApi.V1 ( Address (Address), Credential (PubKeyCredential, ScriptCredential), CurrencySymbol, Script, TxInInfo (TxInInfo), - TxInfo (..), TxOut (TxOut), TxOutRef (TxOutRef), ValidatorHash (ValidatorHash), Value, ) -import PlutusLedgerApi.V1.Interval qualified as Interval (always) import PlutusLedgerApi.V1.Value qualified as Value ( Value (Value), singleton, @@ -36,37 +35,25 @@ import Test.Specification ( scriptSucceeds, ) import Prelude ( - Functor (fmap), Maybe (Nothing), PBool, Semigroup ((<>)), + fmap, pconstant, - pconstantData, pif, + ($), ) currencySymbol :: CurrencySymbol currencySymbol = "deadbeef" -mkTxInfo :: Value -> [TxOut] -> TxInfo -mkTxInfo mint outs = - TxInfo - { txInfoInputs = fmap (TxInInfo (TxOutRef "" 0)) outs - , txInfoOutputs = [] - , txInfoFee = Value.singleton "" "" 1000 - , txInfoMint = mint - , txInfoDCert = [] - , txInfoWdrl = [] - , txInfoValidRange = Interval.always - , txInfoSignatories = [] - , txInfoData = [] - , txInfoId = "" - } +mkInputs :: [TxOut] -> [TxInInfo] +mkInputs = fmap (TxInInfo (TxOutRef "" 0)) singleAuthorityTokenBurnedTest :: Value -> [TxOut] -> Script singleAuthorityTokenBurnedTest mint outs = let actual :: ClosedTerm PBool - actual = singleAuthorityTokenBurned (pconstant currencySymbol) (pconstantData (mkTxInfo mint outs)) (pconstant mint) + actual = singleAuthorityTokenBurned (pconstant currencySymbol) (punsafeCoerce $ pconstant $ mkInputs outs) (pconstant mint) s :: ClosedTerm POpaque s = pif diff --git a/agora-specs/Spec/Governor.hs b/agora-specs/Spec/Governor.hs index cb905de..215cc0a 100644 --- a/agora-specs/Spec/Governor.hs +++ b/agora-specs/Spec/Governor.hs @@ -13,17 +13,11 @@ TODO: Add negative test cases, see [#76](https://github.com/Liqwid-Labs/agora/is -} module Spec.Governor (specs) where -import Agora.Governor (GovernorDatum (..), GovernorRedeemer (..)) -import Agora.Governor.Scripts (governorPolicy, governorValidator) -import Agora.Proposal (ProposalId (..)) -import Data.Default.Class (Default (def)) -import Sample.Governor (createProposal, mintGATs, mintGST, mutateState) -import Sample.Shared qualified as Shared +import Sample.Governor.Initialize qualified as GST +import Sample.Governor.Mutate qualified as Mutate import Test.Specification ( SpecificationTree, group, - policySucceedsWith, - validatorSucceedsWith, ) -- | The SpecificationTree exported by this module. @@ -31,49 +25,38 @@ specs :: [SpecificationTree] specs = [ group "policy" - [ policySucceedsWith - "GST minting" - (governorPolicy Shared.governor) - () - mintGST + [ GST.mkTestCase "totally legal" GST.totallyValidParameters True + , group + "illegal" + [ GST.mkTestCase "invalid thresholds" GST.invalidDatumThresholdsParameters False + , GST.mkTestCase + "invalid max time range width for proposal creation" + GST.invalidDatumMaxTimeRangeWidthParameters + False + , GST.mkTestCase "invalid timings" GST.invalidDatumTimingConfigParameters False + , GST.mkTestCase "no governor datum" GST.withoutGovernorDatumParameters False + , GST.mkTestCase "no witness UTXO" GST.witnessNotPresentedParameters False + , GST.mkTestCase "mint more than one GST" GST.mintMoreThanOneGSTParameters False + , GST.mkTestCase "GST has non-empty name" GST.mintGSTWithNoneEmptyNameParameters False + ] ] , group "validator" - [ validatorSucceedsWith - "proposal creation" - (governorValidator Shared.governor) - ( GovernorDatum - def - (ProposalId 0) - def - def - 3 - ) - CreateProposal - createProposal - , validatorSucceedsWith - "GATs minting" - (governorValidator Shared.governor) - ( GovernorDatum - def - (ProposalId 5) - def - def - 3 - ) - MintGATs - mintGATs - , validatorSucceedsWith - "mutate governor state" - (governorValidator Shared.governor) - ( GovernorDatum - def - (ProposalId 5) - def - def - 3 - ) - MutateGovernor - mutateState + [ group + "mutate" + [ Mutate.mkTestCase + "legal" + Mutate.totallyValidBundle + (Mutate.Validity True) + , group "illegal" $ + map + ( \b -> + Mutate.mkTestCase + "(negative test)" + b + (Mutate.Validity False) + ) + Mutate.invalidBundles + ] ] ] diff --git a/agora-specs/Spec/Proposal.hs b/agora-specs/Spec/Proposal.hs index 9ef2416..6dd51b0 100644 --- a/agora-specs/Spec/Proposal.hs +++ b/agora-specs/Spec/Proposal.hs @@ -40,7 +40,7 @@ specs = "use other's stake" Create.useStakeOwnBySomeoneElseParameters True - False + True False , Create.mkTestTree "altered stake" @@ -93,7 +93,7 @@ specs = mkLegalGroup nCosigners = Cosign.mkTestTree - ("with " <> show nCosigners <> " cosigners") + (unwords ["with", show nCosigners, "cosigners"]) (Cosign.validCosignNParameters nCosigners) True legalGroup = @@ -101,7 +101,7 @@ specs = map mkLegalGroup cosignerCases mkIllegalStatusNotDraftGroup nCosigners = - group ("with " <> show nCosigners <> " cosigners") $ + group (unwords ["with", show nCosigners, "cosigners"]) $ map ( \ps -> Cosign.mkTestTree @@ -133,93 +133,164 @@ specs = [ Vote.mkTestTree "legal" Vote.validVoteParameters True -- TODO: add negative test cases ] - , group "advancing" $ - let mkFromDraft nCosigners = - let name = "with " <> show nCosigners <> " cosigner(s)" + , group + "advancing" + $ let possibleCosigners = [1, 5, 10] + possibleEffects = [1, 2, 5] + in do + cs <- possibleCosigners + es <- possibleEffects - legalGroup = - group - "legal" - [ Advance.mkTestTree - "to next state" - ( head $ - Advance.advanceToNextStateInTimeParameters - nCosigners - ) - True - , Advance.mkTestTree - "to failed state" - ( head $ - Advance.advanceToFailedStateDueToTimeoutParameters - nCosigners - ) - True - ] + let groupName = + unwords + [ "with" + , show cs + , "cosigners" + , "and" + , show es + , "effects" + ] - illegalGroup = - group - "illegal" - [ Advance.mkTestTree - "insufficient cosigns" - (Advance.insufficientCosignsParameters nCosigners) - False - , Advance.mkTestTree - "invalid stake output" - (head $ Advance.invalidOutputStakeParameters nCosigners) - False - ] - in group name [legalGroup, illegalGroup] - - draftGroup = group "from draft" $ map mkFromDraft [1, 5, 10] - - legalGroup = - group - "legal" - [ group "advance to next state" $ - map - ( \ps -> - let name = "from: " <> show ps.fromStatus - in Advance.mkTestTree name ps True - ) - (tail $ Advance.advanceToNextStateInTimeParameters 1) - , group "advance to failed state" $ - map - ( \ps -> - let name = "from: " <> show ps.fromStatus - in Advance.mkTestTree name ps True - ) - (tail $ Advance.advanceToFailedStateDueToTimeoutParameters 1) - ] - - illegalGroup = - group - "illegal" - [ Advance.mkTestTree - "insufficient votes" - Advance.insufficientVotesParameters - False - , Advance.mkTestTree - "initial state is Finished" - Advance.advanceFromFinishedParameters - False - , group - "invalid stake output" - $ do - nStake <- [1, 5] - ps <- tail $ Advance.invalidOutputStakeParameters nStake - - let name = - "from " <> show ps.fromStatus <> "with " - <> show nStake - <> " stakes" - - pure $ Advance.mkTestTree name ps False - ] - in [draftGroup, legalGroup, illegalGroup] + pure $ + group + groupName + [ group + "legal" + $ let allValid = + Advance.Validity + { forProposalValidator = True + , forStakeValidator = True + , forGovernorValidator = Just True + , forAuthorityTokenPolicy = Just True + } + mkName b = + unwords + [ "from" + , show b.proposalParameters.fromStatus + , "to" + , show b.proposalParameters.toStatus + ] + in [ Advance.mkTestTree' + "to next state" + mkName + (Advance.mkValidToNextStateBundles cs es) + allValid + , Advance.mkTestTree' + "to failed state" + mkName + (Advance.mkValidToFailedStateBundles cs es) + allValid + ] + , group + "illegal" + [ Advance.mkTestTree' + "advance finished proposals" + (const "(negative test)") + (Advance.mkFromFinishedBundles cs es) + Advance.Validity + { forProposalValidator = False + , forStakeValidator = True + , forGovernorValidator = Just False + , forAuthorityTokenPolicy = Just True + } + , Advance.mkTestTree + "insufficient cosigns" + (Advance.mkInsufficientCosignsBundle cs es) + Advance.Validity + { forProposalValidator = False + , forStakeValidator = True + , forGovernorValidator = Nothing + , forAuthorityTokenPolicy = Nothing + } + , Advance.mkTestTree + "insufficient votes" + (Advance.mkInsufficientVotesBundle cs es) + Advance.Validity + { forProposalValidator = False + , forStakeValidator = True + , forGovernorValidator = Nothing + , forAuthorityTokenPolicy = Nothing + } + , Advance.mkTestTree + "ambiguous winning effect" + (Advance.mkAmbiguousWinnerBundle cs es) + Advance.Validity + { forProposalValidator = False + , forStakeValidator = True + , forGovernorValidator = Nothing + , forAuthorityTokenPolicy = Nothing + } + , Advance.mkTestTree' + "to next state too late" + (\b -> unwords ["from", show b.proposalParameters.fromStatus]) + (Advance.mkToNextStateTooLateBundles cs es) + Advance.Validity + { forProposalValidator = False + , forStakeValidator = True + , forGovernorValidator = Just True + , forAuthorityTokenPolicy = Just True + } + , Advance.mkTestTree' + "altered output stake datum" + (\b -> unwords ["from", show b.proposalParameters.fromStatus]) + (Advance.mkInvalidOutputStakeBundles cs es) + Advance.Validity + { forProposalValidator = False + , forStakeValidator = False + , forGovernorValidator = Just True + , forAuthorityTokenPolicy = Just True + } + , Advance.mkTestTree + "forget to mint GATs" + (Advance.mkNoGATMintedBundle cs es) + Advance.Validity + { forProposalValidator = True + , forStakeValidator = True + , forGovernorValidator = Just False + , forAuthorityTokenPolicy = Nothing + } + , Advance.mkTestTree + "mint GATs for wrong validators" + (Advance.mkMintGATsForWrongEffectsBundle cs es) + Advance.Validity + { forProposalValidator = True + , forStakeValidator = True + , forGovernorValidator = Just False + , forAuthorityTokenPolicy = Just True + } + , Advance.mkTestTree + "mint GATs with bad token name" + (Advance.mkMintGATsWithoutTagBundle cs es) + Advance.Validity + { forProposalValidator = True + , forStakeValidator = True + , forGovernorValidator = Just False + , forAuthorityTokenPolicy = Just False + } + , Advance.mkTestTree + "wrong GAT datum" + (Advance.mkGATsWithWrongDatumBundle cs es) + Advance.Validity + { forProposalValidator = True + , forStakeValidator = True + , forGovernorValidator = Just False + , forAuthorityTokenPolicy = Just True + } + , Advance.mkTestTree + "invalid governor output datum" + (Advance.mkBadGovernorOutputDatumBundle cs es) + Advance.Validity + { forProposalValidator = True + , forStakeValidator = True + , forGovernorValidator = Just False + , forAuthorityTokenPolicy = Just True + } + ] + ] , group "unlocking" $ let proposalCountCases = [1, 5, 10, 42] - mkSubgroupName nProposals = "with " <> show nProposals <> " proposals" + mkSubgroupName nProposals = unwords ["with", show nProposals, "proposals"] mkLegalGroup nProposals = group @@ -260,9 +331,13 @@ specs = map ( \ps -> let name = - "role: " <> show ps.stakeRole - <> ", status: " - <> show ps.proposalStatus + unwords + [ "role:" + , show ps.stakeRole + , "," + , "status:" + , show ps.proposalStatus + ] in UnlockStake.mkTestTree name ps False ) (UnlockStake.mkRetractVotesWhileNotVoting nProposals) @@ -270,9 +345,12 @@ specs = map ( \ps -> let name = - "status: " <> show ps.proposalStatus - <> "retract votes: " - <> show ps.retractVotes + unwords + [ "status:" + , show ps.proposalStatus + , "retract votes:" + , show ps.retractVotes + ] in UnlockStake.mkTestTree name ps False ) (UnlockStake.mkUnockIrrelevantStakeParameters nProposals) @@ -280,7 +358,8 @@ specs = map ( \ps -> let name = - "status: " <> show ps.proposalStatus + unwords + ["status:", show ps.proposalStatus] in UnlockStake.mkTestTree name ps False ) (UnlockStake.mkRemoveCreatorLockBeforeFinishedParameters nProposals) @@ -292,9 +371,13 @@ specs = map ( \ps -> let name = - "role: " <> show ps.stakeRole - <> ", status: " - <> show ps.proposalStatus + unwords + [ "role:" + , show ps.stakeRole + , "," + , "status:" + , show ps.proposalStatus + ] in UnlockStake.mkTestTree name ps False ) (UnlockStake.mkAlterStakeParameters nProposals) diff --git a/agora-testlib/Test/Util.hs b/agora-testlib/Test/Util.hs index 3fffdc2..3d2c8cb 100644 --- a/agora-testlib/Test/Util.hs +++ b/agora-testlib/Test/Util.hs @@ -17,6 +17,12 @@ module Test.Util ( pubKeyHashes, userCredentials, scriptCredentials, + validatorHashes, + groupsOfN, + withOptional, + mkSpending, + mkMinting, + CombinableBuilder, ) where -------------------------------------------------------------------------------- @@ -29,8 +35,26 @@ import Data.ByteString qualified as BS import Data.ByteString.Char8 qualified as C import Data.ByteString.Lazy qualified as ByteString.Lazy import Data.List (sortOn) +import Plutarch.Context ( + Builder, + UTXO, + buildMintingUnsafe, + buildSpendingUnsafe, + withMinting, + withSpendingOutRef, + ) import Plutarch.Crypto (pblake2b_256) -import PlutusLedgerApi.V1 (Credential (PubKeyCredential, ScriptCredential), PubKeyHash (..), ValidatorHash (ValidatorHash)) +import PlutusLedgerApi.V1 ( + Credential ( + PubKeyCredential, + ScriptCredential + ), + CurrencySymbol, + PubKeyHash (..), + ScriptContext, + TxOutRef, + ValidatorHash (ValidatorHash), + ) import PlutusLedgerApi.V1.Interval qualified as PlutusTx import PlutusLedgerApi.V1.Scripts (Datum (Datum), DatumHash (DatumHash)) import PlutusLedgerApi.V1.Value (Value (..)) @@ -132,6 +156,65 @@ pubKeyHashes = PubKeyHash . PlutusTx.toBuiltin <$> blake2b_224Hashes userCredentials :: [Credential] userCredentials = PubKeyCredential <$> pubKeyHashes +-- | An infinite list of *valid* validator hashes. +validatorHashes :: [ValidatorHash] +validatorHashes = ValidatorHash . PlutusTx.toBuiltin <$> blake2b_224Hashes + -- | An infinite list of *valid* script credentials. scriptCredentials :: [Credential] -scriptCredentials = ScriptCredential . ValidatorHash . PlutusTx.toBuiltin <$> blake2b_224Hashes +scriptCredentials = ScriptCredential <$> validatorHashes + +-------------------------------------------------------------------------------- + +-- | Turn the given list in to groups which have the given length. +groupsOfN :: Int -> [a] -> [[a]] +groupsOfN _ [] = [] +groupsOfN n xs = + let (nextGroup, rest) = next n xs + in nextGroup : groupsOfN n rest + where + next :: Int -> [a] -> ([a], [a]) + next _ [] = ([], []) + next 0 xs = ([], xs) + next n (x : xs) = + let (xs', rest) = next (n - 1) xs + in (x : xs', rest) + +-------------------------------------------------------------------------------- + +-- | Optionally apply a modifier to the given 'UTXO'. +withOptional :: + (a -> UTXO -> UTXO) -> + Maybe a -> + UTXO -> + UTXO +withOptional f (Just b) = f b +withOptional _ _ = id + +{- | Given the builder generator and the parameters, create a 'ScriptContext' + that spends the UTXO that referenced by the given 'TxOutRef'. +-} +mkSpending :: + forall ps. + (forall b. (Monoid b, Builder b) => ps -> b) -> + ps -> + TxOutRef -> + ScriptContext +mkSpending mkBuilder ps oref = + buildSpendingUnsafe $ + mkBuilder ps <> withSpendingOutRef oref + +{- | Given the builder generator and the parameters, create a 'ScriptContext' + that mints the token of the given currency symbol. +-} +mkMinting :: + forall ps. + (forall b. (Monoid b, Builder b) => ps -> b) -> + ps -> + CurrencySymbol -> + ScriptContext +mkMinting mkBuilder ps cs = + buildMintingUnsafe $ + mkBuilder ps <> withMinting cs + +type CombinableBuilder b = (Monoid b, Builder b) diff --git a/agora.cabal b/agora.cabal index cb0283c..8c7d860 100644 --- a/agora.cabal +++ b/agora.cabal @@ -187,7 +187,8 @@ library agora-specs Property.MultiSig Sample.Effect.GovernorMutation Sample.Effect.TreasuryWithdrawal - Sample.Governor + Sample.Governor.Initialize + Sample.Governor.Mutate Sample.Proposal.Advance Sample.Proposal.Cosign Sample.Proposal.Create diff --git a/agora/Agora/AuthorityToken.hs b/agora/Agora/AuthorityToken.hs index 79b8869..448a215 100644 --- a/agora/Agora/AuthorityToken.hs +++ b/agora/Agora/AuthorityToken.hs @@ -100,20 +100,18 @@ authorityTokensValidIn = phoistAcyclic $ {- | Assert that a single authority token has been burned. - @since 0.1.0 + @since 0.2.0 -} singleAuthorityTokenBurned :: forall (keys :: KeyGuarantees) (amounts :: AmountGuarantees) (s :: S). Term s PCurrencySymbol -> - Term s (PAsData PTxInfo) -> + Term s (PBuiltinList (PAsData PTxInInfo)) -> Term s (PValue keys amounts) -> Term s PBool -singleAuthorityTokenBurned gatCs txInfo mint = unTermCont $ do +singleAuthorityTokenBurned gatCs inputs mint = unTermCont $ do let gatAmountMinted :: Term _ PInteger gatAmountMinted = psymbolValueOf # gatCs # mint - txInfoF <- pletFieldsC @'["inputs"] $ txInfo - pure $ foldr1 (#&&) @@ -126,7 +124,7 @@ singleAuthorityTokenBurned gatCs txInfo mint = unTermCont $ do let txOut' = pfield @"resolved" # txInInfo pure $ authorityTokensValidIn # gatCs # pfromData txOut' ) - # txInfoF.inputs + # inputs ] {- | Policy given 'AuthorityToken' params. diff --git a/agora/Agora/Effect.hs b/agora/Agora/Effect.hs index 2239d24..ad4776d 100644 --- a/agora/Agora/Effect.hs +++ b/agora/Agora/Effect.hs @@ -30,7 +30,6 @@ makeEffect :: makeEffect gatCs' f = plam $ \datum _redeemer ctx' -> unTermCont $ do ctx <- pletFieldsC @'["txInfo", "purpose"] ctx' - txInfo' <- pletC ctx.txInfo -- convert input datum, PData, into desierable type -- the way this conversion is performed should be defined @@ -42,14 +41,14 @@ makeEffect gatCs' f = txOutRef' <- pletC (pfield @"_0" # txOutRef) -- fetch minted values to ensure single GAT is burned - txInfo <- pletFieldsC @'["mint"] txInfo' + txInfo <- pletFieldsC @'["mint", "inputs"] ctx.txInfo let mint :: Term _ (PValue _ _) mint = txInfo.mint -- fetch script context gatCs <- pletC $ pconstant gatCs' - pguardC "A single authority token has been burned" $ singleAuthorityTokenBurned gatCs txInfo' mint + pguardC "A single authority token has been burned" $ singleAuthorityTokenBurned gatCs txInfo.inputs mint -- run effect function - pure $ f gatCs datum' txOutRef' txInfo' + pure $ f gatCs datum' txOutRef' ctx.txInfo diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 4b01ebb..aaa0a38 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -23,7 +23,7 @@ import Agora.Governor ( Governor, GovernorDatum, PGovernorDatum, - governorDatumValid, + pisGovernorDatumValid, ) import Agora.Governor.Scripts ( authorityTokenSymbolFromGovernor, @@ -215,7 +215,7 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) -- Ensure the output governor datum is what we want. pguardC "Unexpected governor datum" $ datumF.newDatum #== governorOutputDatum - pguardC "New governor datum should be valid" $ governorDatumValid # governorOutputDatum + pguardC "New governor datum should be valid" $ pisGovernorDatumValid # governorOutputDatum return $ popaque $ pconstant () where diff --git a/agora/Agora/Governor.hs b/agora/Agora/Governor.hs index 7378fe7..ae7acef 100644 --- a/agora/Agora/Governor.hs +++ b/agora/Agora/Governor.hs @@ -20,7 +20,7 @@ module Agora.Governor ( -- * Utilities pgetNextProposalId, getNextProposalId, - governorDatumValid, + pisGovernorDatumValid, ) where import Agora.Proposal ( @@ -28,12 +28,15 @@ import Agora.Proposal ( PProposalThresholds (..), ProposalId (ProposalId), ProposalThresholds, + pisProposalThresholdsValid, ) import Agora.Proposal.Time ( MaxTimeRangeWidth, PMaxTimeRangeWidth, PProposalTimingConfig, ProposalTimingConfig, + pisMaxTimeRangeWidthValid, + pisProposalTimingConfigValid, ) import Agora.SafeMoney (GTTag) import Data.Tagged (Tagged (..)) @@ -44,15 +47,13 @@ import Plutarch.DataRepr ( PDataFields, PIsDataReprInstances (PIsDataReprInstances), ) -import Plutarch.Extra.Comonad (pextract) import Plutarch.Extra.IsData ( DerivePConstantViaEnum (..), EnumIsData (..), ) import Plutarch.Extra.Other (DerivePNewtype' (..)) -import Plutarch.Extra.TermCont (pletC, pletFieldsC, pmatchC) +import Plutarch.Extra.TermCont (pletFieldsC) import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (..)) -import Plutarch.SafeMoney (PDiscrete (..)) import PlutusLedgerApi.V1 (TxOutRef) import PlutusLedgerApi.V1.Value (AssetClass (..)) import PlutusTx qualified @@ -239,27 +240,24 @@ getNextProposalId (ProposalId pid) = ProposalId $ pid + 1 @since 0.1.0 -} -governorDatumValid :: Term s (PGovernorDatum :--> PBool) -governorDatumValid = phoistAcyclic $ +pisGovernorDatumValid :: Term s (PGovernorDatum :--> PBool) +pisGovernorDatumValid = phoistAcyclic $ plam $ \datum -> unTermCont $ do - thresholds <- - pletFieldsC @'["execute", "create", "vote"] $ - pfield @"proposalThresholds" # datum - - PDiscrete execute' <- pmatchC thresholds.execute - PDiscrete draft' <- pmatchC thresholds.create - PDiscrete vote' <- pmatchC thresholds.vote - - execute <- pletC $ pextract # execute' - draft <- pletC $ pextract # draft' - vote <- pletC $ pextract # vote' + datumF <- + pletFieldsC + @'[ "proposalThresholds" + , "proposalTimings" + , "createProposalTimeRangeMaxWidth" + ] + datum pure $ foldr1 (#&&) - [ ptraceIfFalse "Execute threshold is less than or equal to" $ 0 #<= execute - , ptraceIfFalse "Draft threshold is less than or equal to " $ 0 #<= draft - , ptraceIfFalse "Vote threshold is less than or equal to " $ 0 #<= vote - , ptraceIfFalse "Draft threshold is less than vote threshold" $ draft #<= vote - , ptraceIfFalse "Execute threshold is less than vote threshold" $ vote #< execute + [ ptraceIfFalse "thresholds valid" $ + pisProposalThresholdsValid # datumF.proposalThresholds + , ptraceIfFalse "timings valid" $ + pisProposalTimingConfigValid # datumF.proposalTimings + , ptraceIfFalse "time range valid" $ + pisMaxTimeRangeWidthValid # datumF.createProposalTimeRangeMaxWidth ] diff --git a/agora/Agora/Governor/Scripts.hs b/agora/Agora/Governor/Scripts.hs index 6f8c778..13ae7e1 100644 --- a/agora/Agora/Governor/Scripts.hs +++ b/agora/Agora/Governor/Scripts.hs @@ -41,16 +41,17 @@ import Agora.Governor ( Governor (gstOutRef, gtClassRef, maximumCosigners), GovernorRedeemer (..), PGovernorDatum (PGovernorDatum), - governorDatumValid, pgetNextProposalId, + pisGovernorDatumValid, ) import Agora.Proposal ( PProposalDatum (..), Proposal (..), - ProposalStatus (Draft, Finished, Locked), - pemptyVotesFor, + ProposalStatus (Draft, Locked), + phasNeutralEffect, + pisEffectsVotesCompatible, + pisVotesEmpty, pneutralOption, - proposalDatumValid, pwinner, ) import Agora.Proposal.Scripts ( @@ -58,7 +59,6 @@ import Agora.Proposal.Scripts ( proposalValidator, ) import Agora.Proposal.Time (createProposalStartingTime) -import Agora.SafeMoney (GTTag) import Agora.Stake ( PProposalLock (..), PStakeDatum (..), @@ -79,10 +79,6 @@ import Agora.Utils ( validatorHashToAddress, validatorHashToTokenName, ) -import Plutarch.Extra.Record - --------------------------------------------------------------------------------- - import Plutarch.Api.V1 ( PAddress, PCurrencySymbol, @@ -93,7 +89,6 @@ import Plutarch.Api.V1 ( PTxOut, PValidator, PValidatorHash, - PValue, mintingPolicySymbol, mkMintingPolicy, mkValidator, @@ -103,19 +98,18 @@ import Plutarch.Api.V1.AssetClass ( passetClass, passetClassValueOf, ) -import Plutarch.Api.V1.ScriptContext (pfindTxInByTxOutRef, pisUTXOSpent, ptryFindDatum, ptxSignedBy, pvalueSpent) +import Plutarch.Api.V1.ScriptContext (pfindTxInByTxOutRef, pisUTXOSpent, ptryFindDatum, pvalueSpent) import "liqwid-plutarch-extra" Plutarch.Api.V1.Value (psymbolValueOf) +import Plutarch.Extra.Field (pletAllC) import Plutarch.Extra.IsData (pmatchEnumFromData) +import Plutarch.Extra.List (pfirstJust) import Plutarch.Extra.Map ( plookup, plookup', ) import Plutarch.Extra.Maybe (pisDJust) +import Plutarch.Extra.Record (mkRecordConstr, (.&), (.=)) import Plutarch.Extra.TermCont (pguardC, pletC, pletFieldsC, pmatchC, ptryFromC) -import Plutarch.SafeMoney (PDiscrete (..), pvalueDiscrete') - --------------------------------------------------------------------------------- - import PlutusLedgerApi.V1 ( CurrencySymbol (..), MintingPolicy, @@ -186,7 +180,9 @@ governorPolicy gov = let datumHash = pfield @"datumHash" # pfromData govOutput datum = mustFindDatum' @PGovernorDatum # datumHash # txInfoF.datums - pure $ popaque $ governorDatumValid # datum + pguardC "Governor output datum valid" $ pisGovernorDatumValid # datum + + pure $ popaque $ pconstant () {- | Validator for Governors. @@ -277,7 +273,7 @@ governorPolicy gov = governorValidator :: Governor -> ClosedTerm PValidator governorValidator gov = plam $ \datum' redeemer' ctx' -> unTermCont $ do - ctxF <- pletFieldsC @'["txInfo", "purpose"] ctx' + ctxF <- pletAllC ctx' txInfo' <- pletC $ pfromData $ ctxF.txInfo txInfoF <- pletFieldsC @'["mint", "inputs", "outputs", "datums", "signatories", "validRange"] txInfo' @@ -292,15 +288,7 @@ governorValidator gov = let ownAddress = pfromData $ ownInputF.address (pfromData -> (oldGovernorDatum :: Term _ PGovernorDatum), _) <- ptryFromC datum' - oldGovernorDatumF <- - pletFieldsC - @'[ "proposalThresholds" - , "nextProposalId" - , "proposalTimings" - , "createProposalTimeRangeMaxWidth" - , "maximumProposalsPerStake" - ] - oldGovernorDatum + oldGovernorDatumF <- pletAllC oldGovernorDatum -- Check that GST will be returned to the governor. let ownInputGSTAmount = psymbolValueOf # pgstSymbol # ownInputF.value @@ -324,7 +312,8 @@ governorValidator gov = pfromData $ mustBePJust # "Ouput governor state datum not found" #$ ptryFindDatum # outputGovernorStateDatumHash # txInfoF.datums - pguardC "New datum is not valid" $ governorDatumValid # newGovernorDatum + + pguardC "New datum is valid" $ pisGovernorDatumValid # newGovernorDatum pure $ pmatchEnumFromData redeemer' $ \case @@ -354,20 +343,21 @@ governorValidator gov = -- Check that a stake is spent to create the propsal, -- and the value it contains meets the requirement. - stakeInput <- + stakeInputs <- pletC $ - mustBePJust # "Stake input not found" #$ pfind + pfilter # phoistAcyclic ( plam $ - \((pfield @"resolved" #) -> txOut') -> unTermCont $ do - txOut <- pletFieldsC @'["address", "value"] txOut' - - pure $ - txOut.address #== pdata pstakeValidatorAddress - #&& psymbolValueOf # psstSymbol # txOut.value #== 1 + \((pfield @"value" #) . (pfield @"resolved" #) -> value) -> + psymbolValueOf # psstSymbol # value #== 1 ) # pfromData txInfoF.inputs + pguardC "Can process only one stake" $ + plength # stakeInputs #== 1 + + stakeInput <- pletC $ phead # stakeInputs + stakeInputF <- pletFieldsC @'["datumHash", "value"] $ pfield @"resolved" # stakeInput pguardC "Stake input doesn't have datum" $ @@ -375,20 +365,12 @@ governorValidator gov = let stakeInputDatum = mustFindDatum' @PStakeDatum # stakeInputF.datumHash # txInfoF.datums - stakeInputDatumF <- - pletFieldsC @["stakedAmount", "owner", "lockedBy"] stakeInputDatum + stakeInputDatumF <- pletAllC 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) - - -- TODO: Is this required? - pguardC "Tx should be signed by the stake owner" $ - ptxSignedBy # txInfoF.signatories # stakeInputDatumF.owner - -- Check that the newly minted PST is sent to the proposal validator, -- and the datum it carries is legal. @@ -417,92 +399,79 @@ governorValidator gov = # outputDatumHash # txInfoF.datums - pguardC "Proposal datum must be valid" $ - proposalDatumValid' # proposalOutputDatum' + proposalOutputDatum <- pletAllC proposalOutputDatum' - proposalOutputDatum <- - pletFieldsC - @'["effects", "cosigners", "proposalId", "votes"] - proposalOutputDatum' - - pguardC "Proposal should have only one cosigner" $ - plength # pfromData proposalOutputDatum.cosigners #== 1 - - let -- Votes should be empty at this point - expectedVotes = pemptyVotesFor # pfromData proposalOutputDatum.effects - expectedStartingTime = + let expectedStartingTime = createProposalStartingTime # oldGovernorDatumF.createProposalTimeRangeMaxWidth # txInfoF.validRange - -- Id, thresholds and timings should be copied from the old governor state datum. - expectedProposalOut = - mkRecordConstr - PProposalDatum - ( #proposalId .= oldGovernorDatumF.nextProposalId - .& #effects .= proposalOutputDatum.effects - .& #status .= pconstantData Draft - .& #cosigners .= proposalOutputDatum.cosigners - .& #thresholds .= oldGovernorDatumF.proposalThresholds - .& #votes .= pdata expectedVotes - .& #timingConfig .= oldGovernorDatumF.proposalTimings - .& #startingTime .= pdata expectedStartingTime - ) - pguardC "Datum correct" $ expectedProposalOut #== proposalOutputDatum' + expectedCosigners = psingleton @PBuiltinList # stakeInputDatumF.owner - let cosigner = phead # pfromData proposalOutputDatum.cosigners - - pguardC "Cosigner should be the stake owner" $ - pdata stakeInputDatumF.owner #== cosigner + pguardC "Proposal datum correct" $ + foldl1 + (#&&) + [ ptraceIfFalse "has neutral effect" $ + phasNeutralEffect # proposalOutputDatum.effects + , ptraceIfFalse "votes have valid shape" $ + pisEffectsVotesCompatible # proposalOutputDatum.effects # proposalOutputDatum.votes + , ptraceIfFalse "votes are empty" $ + pisVotesEmpty # proposalOutputDatum.votes + , ptraceIfFalse "id correct" $ + proposalOutputDatum.proposalId #== oldGovernorDatumF.nextProposalId + , ptraceIfFalse "status is Draft" $ + proposalOutputDatum.status #== pconstantData Draft + , ptraceIfFalse "cosigners correct" $ + plistEquals # pfromData proposalOutputDatum.cosigners # expectedCosigners + , ptraceIfFalse "starting time correct" $ + proposalOutputDatum.startingTime #== expectedStartingTime + , ptraceIfFalse "copy over configurations" $ + proposalOutputDatum.thresholds #== oldGovernorDatumF.proposalThresholds + #&& proposalOutputDatum.timingConfig #== oldGovernorDatumF.proposalTimings + ] -- Check the output stake has been proposly updated. + let stakeOutputDatumHash = + mustBePJust # "Output stake should be presented" + #$ pfirstJust + # phoistAcyclic + ( plam + ( \txOut -> unTermCont $ do + txOutF <- pletFieldsC @'["datumHash", "value"] txOut - stakeOutput <- - pletC $ - mustBePJust - # "Stake output not found" - #$ pfind - # phoistAcyclic - ( plam $ - \txOut' -> unTermCont $ do - txOut <- pletFieldsC @'["address", "value"] txOut' - - pure $ - txOut.address #== pdata pstakeValidatorAddress - #&& psymbolValueOf # psstSymbol # txOut.value #== 1 - ) - # pfromData txInfoF.outputs - - stakeOutputF <- pletFieldsC @'["datumHash", "value"] $ stakeOutput - - pguardC "Staked GTs should be sent back to stake validator" $ - stakeInputDatumF.stakedAmount #== (pgtValueOf # stakeOutputF.value) - - let stakeOutputDatumHash = mustBePDJust # "Stake output should have datum" # stakeOutputF.datumHash + pure $ + pif + (psymbolValueOf # psstSymbol # txOutF.value #== 1) + ( pcon $ + PJust $ + mustBePDJust # "Output stake datum should be presented" + # txOutF.datumHash + ) + (pcon PNothing) + ) + ) + # pfromData txInfoF.outputs stakeOutputDatum = - mustBePJust # "Stake output not found" #$ ptryFindDatum # stakeOutputDatumHash # txInfoF.datums + mustBePJust @(PAsData PStakeDatum) # "Stake output datum presented" + #$ ptryFindDatum # stakeOutputDatumHash # txInfoF.datums - -- The stake should be locked by the newly created proposal. - let newLock = + stakeOutputLocks = + pfromData $ pfield @"lockedBy" # stakeOutputDatum + + -- The stake should be locked by the newly created proposal. + newLock = mkRecordConstr PCreated ( #created .= oldGovernorDatumF.nextProposalId ) -- Append new locks to existing locks - expectedProposalLocks = pcons # pdata newLock # stakeInputDatumF.lockedBy + expectedProposalLocks = + pcons # pdata newLock # stakeInputDatumF.lockedBy - expectedStakeOutputDatum = - pdata $ - mkRecordConstr - PStakeDatum - ( #stakedAmount .= stakeInputDatumF.stakedAmount - .& #owner .= stakeInputDatumF.owner - .& #lockedBy .= pdata expectedProposalLocks - ) - - pguardC "Unexpected stake output datum" $ expectedStakeOutputDatum #== stakeOutputDatum + pguardC "Stake output locks correct" $ + plistEquals # stakeOutputLocks # expectedProposalLocks pure $ popaque $ pconstant () @@ -533,36 +502,14 @@ governorValidator gov = ) # pfromData txInfoF.inputs - proposalOutputF <- - pletFieldsC @'["datumHash"] $ - mustBePJust # "Proposal output not found" - #$ pfind - # plam - ( \txOut -> unTermCont $ do - txOutF <- pletFieldsC @'["address", "value"] txOut - pure $ - psymbolValueOf # ppstSymbol # txOutF.value #== 1 - #&& txOutF.address #== pdata pproposalValidatorAddress - ) - # pfromData txInfoF.outputs - proposalInputDatum <- pletC $ mustFindDatum' @PProposalDatum # proposalInputF.datumHash # txInfoF.datums - proposalOutputDatum <- - pletC $ - mustFindDatum' @PProposalDatum - # proposalOutputF.datumHash - # txInfoF.datums - - pguardC "Proposal datum must be valid" $ - proposalDatumValid' # proposalInputDatum - #&& proposalDatumValid' # proposalOutputDatum proposalInputDatumF <- - pletFieldsC @'["proposalId", "effects", "status", "cosigners", "thresholds", "votes", "timingConfig", "startingTime"] + pletFieldsC @'["effects", "status", "thresholds", "votes"] proposalInputDatum -- Check that the proposal state is advanced so that a proposal cannot be executed twice. @@ -570,22 +517,6 @@ governorValidator gov = pguardC "Proposal must be in locked(executable) state in order to execute effects" $ proposalInputDatumF.status #== pconstantData Locked - let expectedOutputProposalDatum = - mkRecordConstr - PProposalDatum - ( #proposalId .= proposalInputDatumF.proposalId - .& #effects .= proposalInputDatumF.effects - .& #status .= pconstantData Finished - .& #cosigners .= proposalInputDatumF.cosigners - .& #thresholds .= proposalInputDatumF.thresholds - .& #votes .= proposalInputDatumF.votes - .& #timingConfig .= proposalInputDatumF.timingConfig - .& #startingTime .= proposalInputDatumF.startingTime - ) - - pguardC "Unexpected output proposal datum" $ - pdata proposalOutputDatum #== pdata expectedOutputProposalDatum - -- TODO: anything else to check here? -- Find the highest votes and the corresponding tag. @@ -644,32 +575,32 @@ governorValidator gov = gatOutputValidator = gatOutputValidator' # effectGroup - pure $ - popaque $ - pfoldr - # plam - ( \txOut r -> - let value = pfield @"value" # txOut - atValue = psymbolValueOf # patSymbol # value - in pif (atValue #== 0) r $ - pif (atValue #== 1) (r #&& gatOutputValidator # txOut) $ pconstant False - ) - # pconstant True - # pfromData txInfoF.outputs + pguardC "GATs valid" $ + pfoldr + # plam + ( \txOut r -> + let value = pfield @"value" # txOut + atValue = psymbolValueOf # patSymbol # value + in pif (atValue #== 0) r $ + pif (atValue #== 1) (r #&& gatOutputValidator # txOut) $ pconstant False + ) + # pconstant True + # pfromData txInfoF.outputs + + pure $ popaque $ pconstant () -------------------------------------------------------------------------- Just MutateGovernor -> unTermCont $ do -- Check that a GAT is burnt. - pure $ popaque $ singleAuthorityTokenBurned patSymbol ctxF.txInfo txInfoF.mint + pguardC "One valid GAT burnt" $ + singleAuthorityTokenBurned patSymbol txInfoF.inputs txInfoF.mint + + pure $ popaque $ pconstant () -------------------------------------------------------------------------- Nothing -> ptraceError "Unknown redeemer" where - -- Get th amount of governance tokens in a value. - pgtValueOf :: Term s (PValue _ _ :--> PDiscrete GTTag) - pgtValueOf = phoistAcyclic $ pvalueDiscrete' gov.gtClassRef - -- The currency symbol of authority token. patSymbol :: Term s PCurrencySymbol patSymbol = phoistAcyclic $ pconstant $ authorityTokenSymbolFromGovernor gov @@ -680,24 +611,12 @@ governorValidator gov = let AssetClass (sym, _) = proposalSTAssetClassFromGovernor gov in phoistAcyclic $ pconstant sym - -- Is a proposal state datum valid? - proposalDatumValid' :: Term s (PProposalDatum :--> PBool) - proposalDatumValid' = - let params = proposalFromGovernor gov - in phoistAcyclic $ proposalDatumValid params - -- The address of the proposal validator. pproposalValidatorAddress :: Term s PAddress pproposalValidatorAddress = let vh = proposalValidatorHashFromGovernor gov in phoistAcyclic $ pconstant $ validatorHashToAddress vh - -- The address of the stake validator. - pstakeValidatorAddress :: Term s PAddress - pstakeValidatorAddress = - let vh = stakeValidatorHashFromGovernor gov - in phoistAcyclic $ pconstant $ validatorHashToAddress vh - -- The currency symbol of the stake state token. psstSymbol :: Term s PCurrencySymbol psstSymbol = diff --git a/agora/Agora/Proposal.hs b/agora/Agora/Proposal.hs index 45758d4..cf7bdda 100644 --- a/agora/Agora/Proposal.hs +++ b/agora/Agora/Proposal.hs @@ -29,17 +29,19 @@ module Agora.Proposal ( PResultTag (..), -- * Plutarch helpers - proposalDatumValid, - pemptyVotesFor, + phasNeutralEffect, + pisEffectsVotesCompatible, + pisVotesEmpty, pwinner, pwinner', pneutralOption, pretractVotes, + pisProposalThresholdsValid, ) where import Agora.Proposal.Time (PProposalStartingTime, PProposalTimingConfig, ProposalStartingTime, ProposalTimingConfig) import Agora.SafeMoney (GTTag) -import Agora.Utils (mustBePJust) +import Agora.Utils (withBuiltinPairAsData) import Data.Tagged (Tagged) import GHC.Generics qualified as GHC import Generics.SOP (Generic, I (I)) @@ -50,24 +52,28 @@ import Plutarch.Api.V1 ( PPubKeyHash, PValidatorHash, ) +import Plutarch.Api.V1.AssocMap qualified as PAssocMap import Plutarch.DataRepr (DerivePConstantViaData (..), PDataFields, PIsDataReprInstances (..)) +import Plutarch.Extra.Comonad (pextract) +import Plutarch.Extra.Field (pletAllC) import Plutarch.Extra.IsData ( DerivePConstantViaDataList (..), DerivePConstantViaEnum (..), EnumIsData (..), ProductIsData (ProductIsData), ) -import Plutarch.Extra.List (pnotNull) +import Plutarch.Extra.List (pfirstJust) import Plutarch.Extra.Map qualified as PM import Plutarch.Extra.Map.Unsorted qualified as PUM +import Plutarch.Extra.Maybe (pfromJust) import Plutarch.Extra.Other (DerivePNewtype' (..)) -import Plutarch.Extra.TermCont (pguardC, pletC, pletFieldsC) +import Plutarch.Extra.TermCont (pguardC, pletC, pmatchC) import Plutarch.Lift ( DerivePConstantViaNewtype (..), PConstantDecl, PUnsafeLiftDecl (..), ) -import Plutarch.SafeMoney (PDiscrete) +import Plutarch.SafeMoney (PDiscrete (..)) import Plutarch.Show (PShow (..)) import PlutusLedgerApi.V1 (DatumHash, PubKeyHash, ValidatorHash) import PlutusLedgerApi.V1.Value (AssetClass) @@ -567,27 +573,6 @@ deriving via instance PTryFrom PData (PAsData PProposalVotes) -{- | Retract votes given the option and the amount of votes. - - @since 0.1.0 --} -pretractVotes :: Term s (PResultTag :--> PInteger :--> PProposalVotes :--> PProposalVotes) -pretractVotes = phoistAcyclic $ - plam $ \rt count votes -> - let voteMap :: Term _ (PMap 'Unsorted PResultTag PInteger) - voteMap = pto votes - in pcon $ - PProposalVotes $ - PM.pupdate - # plam - ( \oldCount -> unTermCont $ do - newCount <- pletC $ oldCount - count - pguardC "Resulting vote count greater or equal to 0" $ 0 #<= newCount - pure $ pcon $ PJust newCount - ) - # rt - # voteMap - -- | @since 0.1.0 instance PUnsafeLiftDecl PProposalVotes where type PLifted PProposalVotes = ProposalVotes @@ -597,19 +582,6 @@ deriving via instance (PConstantDecl ProposalVotes) -{- | Plutarch-level version of 'emptyVotesFor'. - - @since 0.1.0 --} -pemptyVotesFor :: forall s a. (PIsData a) => Term s (PMap 'Unsorted PResultTag a :--> PProposalVotes) -pemptyVotesFor = - phoistAcyclic $ - plam - ( \m -> - pcon $ - PProposalVotes $ PM.pmap # plam (const $ pconstant 0) # m - ) - {- | Plutarch-level version of 'ProposalDatum'. @since 0.1.0 @@ -712,27 +684,50 @@ deriving via (DerivePConstantViaData ProposalRedeemer PProposalRedeemer) instanc @since 0.1.0 -} -proposalDatumValid :: Proposal -> Term s (Agora.Proposal.PProposalDatum :--> PBool) -proposalDatumValid proposal = - phoistAcyclic $ - plam $ \datum' -> unTermCont $ do - datum <- pletFieldsC @'["effects", "cosigners", "votes"] $ datum' - let atLeastOneNegativeResult = - pany - # phoistAcyclic - (plam $ \m -> pnull #$ pto $ pfromData $ psndBuiltin # m) - #$ pto - $ pfromData datum.effects +{- | Return true if the effect list contains at least one neutral outcome. - pure $ - foldr1 - (#&&) - [ ptraceIfFalse "Proposal has at least one ResultTag has no effects" atLeastOneNegativeResult - , ptraceIfFalse "Proposal has at least one cosigner" $ pnotNull # pfromData datum.cosigners - , ptraceIfFalse "Proposal has fewer cosigners than the limit" $ plength # pfromData datum.cosigners #<= pconstant proposal.maximumCosigners - , ptraceIfFalse "Proposal votes and effects are compatible with each other" $ PUM.pkeysEqual # datum.effects # pto (pfromData datum.votes) - ] + @since 0.2.0 +-} +phasNeutralEffect :: + forall (s :: S). + Term + s + ( PMap 'Unsorted PResultTag (PMap 'Unsorted PValidatorHash PDatumHash) + :--> PBool + ) +phasNeutralEffect = phoistAcyclic $ PAssocMap.pany # PAssocMap.pnull + +{- | Return true if votes and effects of the proposal have the same key set. + + @since 0.2.0 +-} +pisEffectsVotesCompatible :: + forall (s :: S). + Term + s + ( PMap 'Unsorted PResultTag (PMap 'Unsorted PValidatorHash PDatumHash) + :--> PProposalVotes + :--> PBool + ) +pisEffectsVotesCompatible = phoistAcyclic $ + plam $ \m (pto -> v :: Term _ (PMap _ _ _)) -> + PUM.pkeysEqual # m # v + +{- | Retutns true if vote counts of /all/ the options are zero. + + @since 0.2.0 +-} +pisVotesEmpty :: + forall (s :: S). + Term + s + ( PProposalVotes + :--> PBool + ) +pisVotesEmpty = phoistAcyclic $ + plam $ \(pto -> m :: Term _ (PMap _ _ _)) -> + PAssocMap.pall # plam (#== 0) # m {- | Wrapper for 'pwinner''. When the winner cannot be found, the 'neutral' option will be returned. @@ -817,13 +812,6 @@ phighestVotes = phoistAcyclic $ let l :: Term _ (PBuiltinList _) l = pto $ pto votes - f :: - Term - _ - ( PBuiltinPair (PAsData PResultTag) (PAsData PInteger) - :--> PBuiltinPair (PAsData PResultTag) (PAsData PInteger) - :--> PBuiltinPair (PAsData PResultTag) (PAsData PInteger) - ) f = phoistAcyclic $ plam $ \this last -> let lastVotes = pfromData $ psndBuiltin # last @@ -846,10 +834,57 @@ pneutralOption = phoistAcyclic $ let l :: Term _ (PBuiltinList (PBuiltinPair (PAsData PResultTag) _)) l = pto effects - f :: Term _ (PBuiltinPair (PAsData PResultTag) (PAsData (PMap 'Unsorted _ _)) :--> PBool) f = phoistAcyclic $ - plam $ \((pfromData . (psndBuiltin #) -> el)) -> - let el' :: Term _ (PBuiltinList _) - el' = pto el - in pnull # el' - in pfromData $ pfstBuiltin #$ mustBePJust # "No neutral option" #$ pfind # f # l + plam $ + withBuiltinPairAsData $ \rt el -> + pif + (PAssocMap.pnull # el) + (pcon $ PJust rt) + (pcon PNothing) + in pfromJust #$ pfirstJust # f # l + +{- | Return true if the thresholds are valid. + + @since 0.2.0 +-} +pisProposalThresholdsValid :: forall (s :: S). Term s (PProposalThresholds :--> PBool) +pisProposalThresholdsValid = phoistAcyclic $ + plam $ \thresholds -> unTermCont $ do + thresholdsF <- pletAllC thresholds + + PDiscrete execute' <- pmatchC thresholdsF.execute + PDiscrete draft' <- pmatchC thresholdsF.create + PDiscrete vote' <- pmatchC thresholdsF.vote + + execute <- pletC $ pextract # execute' + draft <- pletC $ pextract # draft' + vote <- pletC $ pextract # vote' + + pure $ + foldr1 + (#&&) + [ ptraceIfFalse "Execute threshold is less than or equal to 0" $ 0 #<= execute + , ptraceIfFalse "Draft threshold is less than or equal to 0" $ 0 #<= draft + , ptraceIfFalse "Vote threshold is less than or equal to 0" $ 0 #<= vote + ] + +{- | Retract votes given the option and the amount of votes. + + @since 0.1.0 +-} +pretractVotes :: Term s (PResultTag :--> PInteger :--> PProposalVotes :--> PProposalVotes) +pretractVotes = phoistAcyclic $ + plam $ \rt count votes -> + let voteMap :: Term _ (PMap 'Unsorted PResultTag PInteger) + voteMap = pto votes + in pcon $ + PProposalVotes $ + PM.pupdate + # plam + ( \oldCount -> unTermCont $ do + newCount <- pletC $ oldCount - count + pguardC "Resulting vote count greater or equal to 0" $ 0 #<= newCount + pure $ pcon $ PJust newCount + ) + # rt + # voteMap diff --git a/agora/Agora/Proposal/Scripts.hs b/agora/Agora/Proposal/Scripts.hs index e6424b2..247b56e 100644 --- a/agora/Agora/Proposal/Scripts.hs +++ b/agora/Agora/Proposal/Scripts.hs @@ -14,7 +14,7 @@ import Agora.Proposal ( PProposalDatum (PProposalDatum), PProposalRedeemer (..), PProposalVotes (PProposalVotes), - Proposal (governorSTAssetClass, stakeSTAssetClass), + Proposal (..), ProposalStatus (..), pretractVotes, pwinner', @@ -40,7 +40,6 @@ import Agora.Utils ( getMintingPolicySymbol, mustBePJust, mustFindDatum', - pisUniq', pltAsData, ) import Plutarch.Api.V1 ( @@ -62,8 +61,9 @@ import Plutarch.Api.V1.ScriptContext ( ) import "liqwid-plutarch-extra" Plutarch.Api.V1.Value (psymbolValueOf) import Plutarch.Extra.Comonad (pextract) +import Plutarch.Extra.Field (pletAllC) import Plutarch.Extra.IsData (pmatchEnum) -import Plutarch.Extra.List (pmapMaybe, pmergeBy, pmsortBy) +import Plutarch.Extra.List (pisUniq', pmapMaybe, pmergeBy, pmsortBy) import Plutarch.Extra.Map (plookup, pupdate) import Plutarch.Extra.Maybe (pfromDJust, pfromJust, pisJust) import Plutarch.Extra.Record (mkRecordConstr, (.&), (.=)) @@ -76,7 +76,7 @@ import Plutarch.Extra.TermCont ( ) import Plutarch.SafeMoney (PDiscrete (..)) import Plutarch.Unsafe (punsafeCoerce) -import PlutusLedgerApi.V1.Value (AssetClass (AssetClass)) +import PlutusLedgerApi.V1.Value (AssetClass (AssetClass, unAssetClass)) {- | Policy for Proposals. @@ -105,24 +105,20 @@ proposalPolicy :: proposalPolicy (AssetClass (govCs, govTn)) = plam $ \_redeemer ctx' -> unTermCont $ do PScriptContext ctx' <- pmatchC ctx' - ctx <- pletFieldsC @'["txInfo", "purpose"] ctx' + ctx <- pletAllC ctx' PTxInfo txInfo' <- pmatchC $ pfromData ctx.txInfo txInfo <- pletFieldsC @'["inputs", "mint"] txInfo' - PMinting _ownSymbol <- pmatchC $ pfromData ctx.purpose - - let inputs = txInfo.inputs - mintedValue = pfromData txInfo.mint PMinting ownSymbol' <- pmatchC $ pfromData ctx.purpose let mintedProposalST = passetClassValueOf - # mintedValue + # pfromData txInfo.mint # (passetClass # (pfield @"_0" # ownSymbol') # pconstant "") pguardC "Governance state-thread token must move" $ pisTokenSpent # (passetClass # pconstant govCs # pconstant govTn) - # inputs + # txInfo.inputs pguardC "Minted exactly one proposal ST" $ mintedProposalST #== 1 @@ -184,22 +180,11 @@ proposalValidator proposal = (pfromData -> proposalRedeemer, _) <- ptryFromC @(PAsData PProposalRedeemer) redeemer - proposalF <- - pletFieldsC - @'[ "proposalId" - , "effects" - , "status" - , "cosigners" - , "thresholds" - , "votes" - , "timingConfig" - , "startingTime" - ] - proposalDatum + proposalF <- pletAllC proposalDatum ownAddress <- pletC $ txOutF.address - thresholdsF <- pletFieldsC @'["execute", "create", "vote"] proposalF.thresholds + thresholdsF <- pletAllC proposalF.thresholds currentStatus <- pletC $ pfromData $ proposalF.status @@ -222,7 +207,7 @@ proposalValidator proposal = mustBePJust # "Own output should be present" #$ pfind # plam ( \input -> unTermCont $ do - inputF <- pletFieldsC @'["address", "value", "datumHash"] input + inputF <- pletAllC input -- TODO: this is highly inefficient: O(n) for every output, -- Maybe we can cache the sorted datum map? @@ -407,7 +392,7 @@ proposalValidator proposal = withSingleStake val = withSingleStake' #$ plam $ \stakeIn stakeOut stakeUnchange -> unTermCont $ do - stakeInF <- pletFieldsC @'["stakedAmount", "lockedBy", "owner"] stakeIn + stakeInF <- pletAllC stakeIn val stakeInF stakeOut stakeUnchange @@ -429,6 +414,9 @@ proposalValidator proposal = # newSigs # proposalF.cosigners + pguardC "Less cosigners than maximum limit" $ + plength # updatedSigs #< pconstant proposal.maximumCosigners + pguardC "Cosigners are unique" $ pisUniq' # updatedSigs @@ -663,12 +651,29 @@ proposalValidator proposal = pguardC "Cannot advance ahead of time" notTooEarly pguardC "Finished proposals cannot be advanced" $ pnot # isFinished + let gstSymbol = + pconstant $ + fst $ + unAssetClass proposal.governorSTAssetClass + + gstMoved <- + pletC $ + pany + # plam + ( \( (pfield @"value" #) + . (pfield @"resolved" #) + . pfromData -> + value + ) -> + psymbolValueOf # gstSymbol # value #== 1 + ) + # txInfoF.inputs + let toFailedState = unTermCont $ do pguardC "Proposal should fail: not on time" $ proposalOutStatus #== pconstant Finished - -- TODO: Should check that the GST is not moved - -- if the proposal is in 'Locked' state. + pguardC "GST not moved" $ pnot # gstMoved pure $ pconstant () @@ -689,6 +694,8 @@ proposalValidator proposal = pguardC "Proposal status set to Finished" $ proposalOutStatus #== pconstant Finished + pguardC "GST moved" gstMoved + -- TODO: Perform other necessary checks. pure $ pconstant () _ -> pconstant () diff --git a/agora/Agora/Proposal/Time.hs b/agora/Agora/Proposal/Time.hs index 640552b..b272834 100644 --- a/agora/Agora/Proposal/Time.hs +++ b/agora/Agora/Proposal/Time.hs @@ -26,6 +26,8 @@ module Agora.Proposal.Time ( isVotingPeriod, isLockingPeriod, isExecutionPeriod, + pisProposalTimingConfigValid, + pisMaxTimeRangeWidthValid, ) where import Agora.Plutarch.Orphans () @@ -44,7 +46,8 @@ import Plutarch.DataRepr ( PDataFields, PIsDataReprInstances (..), ) -import Plutarch.Extra.TermCont (pguardC, pletFieldsC, pmatchC) +import Plutarch.Extra.Field (pletAllC) +import Plutarch.Extra.TermCont (pguardC, pmatchC) import Plutarch.Lift ( DerivePConstantViaNewtype (..), PConstantDecl, @@ -273,6 +276,43 @@ deriving via -------------------------------------------------------------------------------- +{- | Return true if the timing configuration is valid. + + @since 0.2.0 +-} +pisProposalTimingConfigValid :: Term s (PProposalTimingConfig :--> PBool) +pisProposalTimingConfigValid = phoistAcyclic $ + plam $ \conf -> unTermCont $ do + confF <- pletAllC conf + + -- everything is greater or equal 0 + pure $ + ptraceIfFalse "ge 0" $ + foldr + ( \t -> + (#&&) + ( pconstant 0 + #<= pfromData t + ) + ) + (pconstant True) + [ confF.draftTime + , confF.votingTime + , confF.lockingTime + , confF.executingTime + ] + +{- | Return true if the maximum time width is greater than 0. + + @since 0.2.0 +-} +pisMaxTimeRangeWidthValid :: Term s (PMaxTimeRangeWidth :--> PBool) +pisMaxTimeRangeWidthValid = + phoistAcyclic $ + plam $ + ptraceIfFalse "greater than 0" + . (pconstant (MaxTimeRangeWidth 0) #<) + {- | Get the starting time of a proposal, from the 'PlutusLedgerApi.V1.txInfoValidPeriod' field. For every proposal, this is only meant to run once upon creation. Given time range should be tight enough, meaning that the width of the time range should be less than the maximum value. @@ -308,11 +348,11 @@ currentProposalTime :: forall (s :: S). Term s (PPOSIXTimeRange :--> PProposalTi currentProposalTime = phoistAcyclic $ plam $ \iv -> unTermCont $ do PInterval iv' <- pmatchC iv - ivf <- pletFieldsC @'["from", "to"] iv' + ivf <- pletAllC iv' PLowerBound lb <- pmatchC ivf.from PUpperBound ub <- pmatchC ivf.to - lbf <- pletFieldsC @'["_0", "_1"] lb - ubf <- pletFieldsC @'["_0", "_1"] ub + lbf <- pletAllC lb + ubf <- pletAllC ub pure $ pcon $ PProposalTime diff --git a/agora/Agora/Stake.hs b/agora/Agora/Stake.hs index cb14229..0dff631 100644 --- a/agora/Agora/Stake.hs +++ b/agora/Agora/Stake.hs @@ -45,19 +45,21 @@ import Plutarch.DataRepr ( PDataFields, PIsDataReprInstances (PIsDataReprInstances), ) +import Plutarch.Extra.Field (pletAll) import Plutarch.Extra.IsData ( DerivePConstantViaDataList (..), ProductIsData (ProductIsData), ) import Plutarch.Extra.List (pnotNull) import Plutarch.Extra.Other (DerivePNewtype' (..)) +import Plutarch.Extra.Sum (PSum (..)) +import Plutarch.Extra.Traversable (pfoldMap) 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 (..)) -------------------------------------------------------------------------------- @@ -117,7 +119,7 @@ data ProposalLock -- ^ 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 + -- This kind of lock is placed while voting on a proposal, in order to -- prevent depositing and withdrawing when votes are in place. -- -- @since 0.2.0 @@ -396,21 +398,14 @@ pnumCreatedProposals :: Term s (PBuiltinList (PAsData PProposalLock) :--> PInteg pnumCreatedProposals = phoistAcyclic $ plam $ \l -> - pfoldl - # phoistAcyclic - ( plam - ( \c (pfromData -> lock) -> - c - + pmatch - lock - ( \case - PCreated _ -> 1 - _ -> 0 - ) - ) - ) - # 0 - # l + pto $ + pfoldMap + # plam + ( \(pfromData -> lock) -> pmatch lock $ \case + PCreated _ -> pcon $ PSum 1 + _ -> mempty + ) + # l {- | The role of a stake for a particular proposal. Scott-encoded. @@ -421,13 +416,13 @@ data PStakeRole (s :: S) PVoter (Term s PResultTag) -- ^ The option which was voted for. - | -- | The stake was used to create the propsoal. + | -- | The stake was used to create the proposal. 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. + | -- | The stake has nothing to do with the given proposal. PIrrelevant deriving stock ( -- | @since 0.2.0 @@ -507,7 +502,7 @@ pgetStakeRole = phoistAcyclic $ (pid' #== pid) (pcon PCreator) (pcon PIrrelevant) - PVoted lock' -> pletFields @'["votedOn", "votedFor"] lock' $ \lockF -> + PVoted lock' -> pletAll lock' $ \lockF -> pif (lockF.votedOn #== pid) (pcon $ PVoter lockF.votedFor) diff --git a/agora/Agora/Treasury.hs b/agora/Agora/Treasury.hs index 16d5a51..bc7cc73 100644 --- a/agora/Agora/Treasury.hs +++ b/agora/Agora/Treasury.hs @@ -114,14 +114,13 @@ treasuryValidator gatCs' = plam $ \_datum redeemer ctx' -> unTermCont $ do redeemer #== pforgetData (pconstantData SpendTreasuryGAT) -- Get the minted value from txInfo. - txInfo' <- pletC ctx.txInfo - txInfo <- pletFieldsC @'["mint"] txInfo' + txInfo <- pletFieldsC @'["mint", "inputs"] ctx.txInfo let mint :: Term _ (PValue _ _) mint = txInfo.mint gatCs <- pletC $ pconstant gatCs' pguardC "A single authority token has been burned" $ - singleAuthorityTokenBurned gatCs txInfo' mint + singleAuthorityTokenBurned gatCs txInfo.inputs mint pure . popaque $ pconstant () diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index e8945c2..166451d 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE QuantifiedConstraints #-} + {- | Module : Agora.Utils Maintainer : emi@haskell.fyi @@ -20,8 +22,8 @@ module Agora.Utils ( isScriptAddress, isPubKey, pltAsData, - pisUniqBy', - pisUniq', + pon, + withBuiltinPairAsData, ) where import Plutarch.Api.V1 ( @@ -209,35 +211,32 @@ pltAsData = phoistAcyclic $ plam $ \(pfromData -> l) (pfromData -> r) -> l #< r -{- | Special version of 'pisUniq'', the list elements should have 'PEq' instance. +{- | Plutarch level 'Data.Function.on'. - @since 0.2.0 + @since 0.2.0 -} -pisUniq' :: - forall (l :: PType -> PType) (a :: PType) (s :: S). - (PEq a, PIsListLike l a) => - Term s (l a :--> PBool) -pisUniq' = phoistAcyclic $ pisUniqBy' # phoistAcyclic (plam (#==)) +pon :: + forall (a :: PType) (b :: PType) (c :: PType) (s :: S). + Term s ((b :--> b :--> c) :--> (a :--> b) :--> a :--> a :--> c) +pon = phoistAcyclic $ + plam $ \f g x y -> + let a = g # x + b = g # y + in f # a # b -{- | Return true if all the elements in the given list are unique, given the equalator function. - The list is assumed to be ordered. +{- | Extract data stored in a 'PBuiltinPair' and call a function to process it. - @since 0.2.0 + @since 0.2.0 -} -pisUniqBy' :: - forall (l :: PType -> PType) (a :: PType) (s :: S). - (PIsListLike l a) => - Term s ((a :--> a :--> PBool) :--> l a :--> PBool) -pisUniqBy' = phoistAcyclic $ - plam $ \eq l -> - pif (pnull # l) (pconstant True) $ - go # eq # (phead # l) # (ptail # l) - where - go :: Term _ ((a :--> a :--> PBool) :--> a :--> l a :--> PBool) - go = phoistAcyclic $ - pfix #$ plam $ \self' eq x xs -> - plet (self' # eq) $ \self -> - pif (pnull # xs) (pconstant True) $ - plet (phead # xs) $ \x' -> - pif (eq # x # x') (pconstant False) $ - self # x' #$ ptail # xs +withBuiltinPairAsData :: + forall (a :: PType) (b :: PType) (c :: PType) (s :: S). + (PIsData a, PIsData b) => + (Term s a -> Term s b -> Term s c) -> + Term + s + (PBuiltinPair (PAsData a) (PAsData b)) -> + Term s c +withBuiltinPairAsData f p = + let a = pfromData $ pfstBuiltin # p + b = pfromData $ psndBuiltin # p + in f a b diff --git a/bench.csv b/bench.csv index 8dd401c..1b0cc51 100644 --- a/bench.csv +++ b/bench.csv @@ -1,234 +1,577 @@ 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,88940927,246756,8891 -Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass,107090537,296185,3627 +Agora/Effects/Treasury Withdrawal Effect/effect/Simple,333137234,829671,3674 +Agora/Effects/Treasury Withdrawal Effect/effect/Simple with multiple treasuries ,492197164,1196783,3986 +Agora/Effects/Treasury Withdrawal Effect/effect/Mixed Assets,455817227,1103968,3859 +Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/governor validator should pass,93089688,256879,8290 +Agora/Effects/Governor Mutation Effect/validator/valid new governor datum/effect validator should pass,112671240,312571,3751 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,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 +Agora/Stake/validator/stakeDepositWithdraw deposit,183506412,498838,4753 +Agora/Stake/validator/stakeDepositWithdraw withdraw,183506412,498838,4741 +Agora/Proposal/policy (proposal creation)/legal/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/legal/governor,324511293,861435,8769 +Agora/Proposal/policy (proposal creation)/legal/stake,153960499,403133,5407 +Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/illegal/invalid next proposal id/stake,153960499,403133,5407 +Agora/Proposal/policy (proposal creation)/illegal/use other's stake/proposal,33689644,100286,1974 +Agora/Proposal/policy (proposal creation)/illegal/use other's stake/governor,324511293,861435,8738 +Agora/Proposal/policy (proposal creation)/illegal/altered stake/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/proposal,33689644,100286,2013 +Agora/Proposal/policy (proposal creation)/illegal/invalid stake locks/stake,159394159,417783,5415 +Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/proposal,33689644,100286,2025 +Agora/Proposal/policy (proposal creation)/illegal/has reached maximum proposals limit/stake,160422991,421241,5437 +Agora/Proposal/policy (proposal creation)/illegal/loose time range/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/illegal/loose time range/stake,153960499,403133,5407 +Agora/Proposal/policy (proposal creation)/illegal/open time range/proposal,33689644,100286,2001 +Agora/Proposal/policy (proposal creation)/illegal/open time range/stake,153960499,403133,5403 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/VotingReady/stake,153960499,403133,5407 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Locked/stake,153960499,403133,5407 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/proposal,33689644,100286,2005 +Agora/Proposal/policy (proposal creation)/illegal/invalid proposal status/Finished/stake,153960499,403133,5407 +Agora/Proposal/validator/cosignature/legal/with 1 cosigners/proposal,235543219,658307,8363 +Agora/Proposal/validator/cosignature/legal/with 1 cosigners/stake,124051829,322526,5215 +Agora/Proposal/validator/cosignature/legal/with 5 cosigners/proposal,670567262,1868918,10993 +Agora/Proposal/validator/cosignature/legal/with 5 cosigners/stake,554847017,1464934,7725 +Agora/Proposal/validator/cosignature/legal/with 10 cosigners/proposal,1328689536,3642435,14281 +Agora/Proposal/validator/cosignature/legal/with 10 cosigners/stake,1102819358,2917719,10862 +Agora/Proposal/validator/cosignature/illegal/duplicate cosigners/stake,124051829,322526,5215 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: VotingReady/stake,124051829,322526,5215 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Locked/stake,124051829,322526,5215 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 1 cosigners/status: Finished/stake,124051829,322526,5215 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: VotingReady/stake,554847017,1464934,7725 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Locked/stake,554847017,1464934,7725 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 5 cosigners/status: Finished/stake,554847017,1464934,7725 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: VotingReady/stake,1102819358,2917719,10862 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Locked/stake,1102819358,2917719,10862 +Agora/Proposal/validator/cosignature/illegal/proposal status not Draft/with 10 cosigners/status: Finished/stake,1102819358,2917719,10862 +Agora/Proposal/validator/voting/legal/proposal,253679830,711967,8345 +Agora/Proposal/validator/voting/legal/stake,141289029,371279,5241 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,248836586,692474,8858 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/stake,134460930,348994,5551 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,292528703,801889,8867 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,5558 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,340029740,936478,10019 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,6710 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,474044919,1182110,10085 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,3653 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,243781894,681753,8860 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,5553 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,279014261,764750,8861 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,5554 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,280145239,767154,8861 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,5554 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,134460930,348994,5551 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,5558 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,6710 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,3653 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/insufficient cosigns/stake,134460930,348994,5551 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/insufficient votes/stake,135183466,351258,5554 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/ambiguous winning effect/stake,135183466,351258,5562 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Draft/stake,134460930,348994,5553 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,5558 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/stake,191489761,484291,6710 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,474044919,1182110,10085 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15806303,48240,3653 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/altered output stake datum/from Locked/governor,474044919,1182110,10086 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,3654 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/forget to mint GATs/proposal,315778694,863869,9307 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/forget to mint GATs/stake,178389602,458680,5998 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,348113422,960681,10246 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,6937 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,3880 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,340029740,936478,9841 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/mint GATs with bad token name/stake,191489761,484291,6532 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/proposal,340029740,936478,10013 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/stake,191489761,484291,6704 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/wrong GAT datum/authority,15806303,48240,3647 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/proposal,340029740,936478,10019 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/stake,191489761,484291,6710 +Agora/Proposal/validator/advancing/with 1 cosigners and 1 effects/illegal/invalid governor output datum/authority,15806303,48240,3653 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,294237934,810566,9447 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/stake,134460930,348994,5944 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,341624937,929969,9456 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,5951 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,385431088,1054570,10609 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,7104 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,493963090,1236555,10479 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,4047 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,289183242,799845,9449 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,5946 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,324415609,882842,9450 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,5947 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,325546587,885246,9450 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,5947 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,134460930,348994,5944 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,5951 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,7104 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,4047 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/insufficient cosigns/stake,134460930,348994,5944 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/insufficient votes/stake,135183466,351258,5947 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/ambiguous winning effect/stake,135183466,351258,5959 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Draft/stake,134460930,348994,5946 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,5951 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/stake,191489761,484291,7104 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,493963090,1236555,10479 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15806303,48240,4047 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/altered output stake datum/from Locked/governor,493963090,1236555,10480 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,4048 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/forget to mint GATs/proposal,361180042,981961,9897 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/forget to mint GATs/stake,178389602,458680,6392 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,393514770,1078773,10836 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,7331 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,4274 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,385431088,1054570,10430 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/mint GATs with bad token name/stake,191489761,484291,6925 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/proposal,385431088,1054570,10603 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/stake,191489761,484291,7098 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/wrong GAT datum/authority,15806303,48240,4041 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/proposal,385431088,1054570,10609 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/stake,191489761,484291,7104 +Agora/Proposal/validator/advancing/with 1 cosigners and 2 effects/illegal/invalid governor output datum/authority,15806303,48240,4047 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,430441978,1164842,11219 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/stake,134460930,348994,7125 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,488913639,1314209,11228 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,7132 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,521635132,1408846,12380 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,8284 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,553717603,1399890,11659 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,5227 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,425387286,1154121,11221 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,7127 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,460619653,1237118,11222 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,7128 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,461750631,1239522,11222 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,7128 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,134460930,348994,7125 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,7132 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,8284 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,5227 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/insufficient cosigns/stake,134460930,348994,7125 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/insufficient votes/stake,135183466,351258,7128 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/ambiguous winning effect/stake,135183466,351258,7152 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Draft/stake,134460930,348994,7127 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,7132 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/stake,191489761,484291,8284 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,553717603,1399890,11659 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15806303,48240,5227 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/altered output stake datum/from Locked/governor,553717603,1399890,11660 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,5228 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/forget to mint GATs/proposal,497384086,1336237,11669 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/forget to mint GATs/stake,178389602,458680,7573 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,529718814,1433049,12607 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,8511 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,5454 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,521635132,1408846,12202 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/mint GATs with bad token name/stake,191489761,484291,8106 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/proposal,521635132,1408846,12374 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/stake,191489761,484291,8278 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/wrong GAT datum/authority,15806303,48240,5221 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/proposal,521635132,1408846,12380 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/stake,191489761,484291,8284 +Agora/Proposal/validator/advancing/with 1 cosigners and 5 effects/illegal/invalid governor output datum/authority,15806303,48240,5227 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,612521495,1742349,11604 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/stake,551883126,1452458,8176 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,314898051,863953,9224 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,5794 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,362399088,998542,10376 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,6946 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,481232867,1202798,10322 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,3890 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,266151242,743817,9217 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,5789 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,301383609,826814,9218 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,5790 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,302514587,829218,9218 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,5790 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,551883126,1452458,8176 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,5794 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,6946 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,3890 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/insufficient cosigns/stake,564514824,1489336,8176 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/insufficient votes/stake,135183466,351258,5790 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/ambiguous winning effect/stake,135183466,351258,5798 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Draft/stake,551883126,1452458,8178 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,5794 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/stake,191489761,484291,6946 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,481232867,1202798,10322 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15806303,48240,3890 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/altered output stake datum/from Locked/governor,481232867,1202798,10323 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,3891 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/forget to mint GATs/proposal,338148042,925933,9664 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/forget to mint GATs/stake,178389602,458680,6234 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,370482770,1022745,10603 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,7173 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,4117 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,362399088,998542,10198 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/mint GATs with bad token name/stake,191489761,484291,6768 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/proposal,362399088,998542,10370 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/stake,191489761,484291,6940 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/wrong GAT datum/authority,15806303,48240,3884 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/proposal,362399088,998542,10376 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/stake,191489761,484291,6946 +Agora/Proposal/validator/advancing/with 5 cosigners and 1 effects/illegal/invalid governor output datum/authority,15806303,48240,3890 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,657922843,1860441,12195 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/stake,551883126,1452458,8570 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,363994285,992033,9814 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,6187 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,407800436,1116634,10967 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,7340 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,501151038,1257243,10716 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,4284 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,311552590,861909,9807 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,6182 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,346784957,944906,9808 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,6183 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,347915935,947310,9808 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,6183 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,551883126,1452458,8570 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,6187 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,7340 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,4284 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/insufficient cosigns/stake,564514824,1489336,8570 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/insufficient votes/stake,135183466,351258,6183 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/ambiguous winning effect/stake,135183466,351258,6195 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Draft/stake,551883126,1452458,8572 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,6187 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/stake,191489761,484291,7340 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,501151038,1257243,10716 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15806303,48240,4284 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/altered output stake datum/from Locked/governor,501151038,1257243,10717 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,4285 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/forget to mint GATs/proposal,383549390,1044025,10255 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/forget to mint GATs/stake,178389602,458680,6628 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,415884118,1140837,11194 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,7567 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,4511 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,407800436,1116634,10788 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/mint GATs with bad token name/stake,191489761,484291,7161 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/proposal,407800436,1116634,10961 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/stake,191489761,484291,7334 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/wrong GAT datum/authority,15806303,48240,4278 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/proposal,407800436,1116634,10967 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/stake,191489761,484291,7340 +Agora/Proposal/validator/advancing/with 5 cosigners and 2 effects/illegal/invalid governor output datum/authority,15806303,48240,4284 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,794126887,2214717,13965 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/stake,551883126,1452458,9750 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,511282987,1376273,11585 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,7368 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,544004480,1470910,12737 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,8520 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,560905551,1420578,11896 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,5464 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,447756634,1216185,11578 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,7363 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,482989001,1299182,11579 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,7364 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,484119979,1301586,11579 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,7364 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,551883126,1452458,9750 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,7368 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,8520 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,5464 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/insufficient cosigns/stake,564514824,1489336,9750 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/insufficient votes/stake,135183466,351258,7364 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/ambiguous winning effect/stake,135183466,351258,7388 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Draft/stake,551883126,1452458,9752 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,7368 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/stake,191489761,484291,8520 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,560905551,1420578,11896 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15806303,48240,5464 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/altered output stake datum/from Locked/governor,560905551,1420578,11897 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,5465 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/forget to mint GATs/proposal,519753434,1398301,12026 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/forget to mint GATs/stake,178389602,458680,7809 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,552088162,1495113,12964 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,8747 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,5691 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,544004480,1470910,12559 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/mint GATs with bad token name/stake,191489761,484291,8342 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/proposal,544004480,1470910,12731 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/stake,191489761,484291,8514 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/wrong GAT datum/authority,15806303,48240,5458 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/proposal,544004480,1470910,12737 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/stake,191489761,484291,8520 +Agora/Proposal/validator/advancing/with 5 cosigners and 5 effects/illegal/invalid governor output datum/authority,15806303,48240,5464 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/proposal,1145091822,3281720,15043 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Draft to VotingReady/stake,1166720427,3099963,11464 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/proposal,342859736,941533,9676 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,6095 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/proposal,390360773,1076122,10828 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,7247 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/governor,490217802,1228658,10623 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,4191 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Draft to Finished/proposal,294112927,821397,9669 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,6090 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/proposal,329345294,904394,9670 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,6091 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Locked to Finished/proposal,330476272,906798,9670 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,6091 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,1166720427,3099963,11464 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,6095 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,7247 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,4191 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/insufficient cosigns/stake,1113969753,2946253,11464 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/insufficient votes/stake,135183466,351258,6091 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/ambiguous winning effect/stake,135183466,351258,6099 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Draft/stake,1166720427,3099963,11466 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,6095 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/stake,191489761,484291,7247 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/governor,490217802,1228658,10623 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/to next state too late/from Locked/authority,15806303,48240,4191 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/altered output stake datum/from Locked/governor,490217802,1228658,10624 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,4192 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/forget to mint GATs/proposal,366109727,1003513,10117 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/forget to mint GATs/stake,178389602,458680,6536 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/proposal,398444455,1100325,11055 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,7474 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,4418 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs with bad token name/proposal,390360773,1076122,10650 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/mint GATs with bad token name/stake,191489761,484291,7069 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/proposal,390360773,1076122,10822 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/stake,191489761,484291,7241 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/wrong GAT datum/authority,15806303,48240,4185 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/proposal,390360773,1076122,10828 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/stake,191489761,484291,7247 +Agora/Proposal/validator/advancing/with 10 cosigners and 1 effects/illegal/invalid governor output datum/authority,15806303,48240,4191 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/proposal,1190493170,3399812,15632 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Draft to VotingReady/stake,1166720427,3099963,11857 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/proposal,391955970,1069613,10265 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,6488 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/proposal,435762121,1194214,11418 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,7641 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/governor,510135973,1283103,11017 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,4585 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Draft to Finished/proposal,339514275,939489,10258 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,6483 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/proposal,374746642,1022486,10259 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,6484 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Locked to Finished/proposal,375877620,1024890,10259 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,6484 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,1166720427,3099963,11857 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,6488 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,7641 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,4585 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/insufficient cosigns/stake,1113969753,2946253,11857 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/insufficient votes/stake,135183466,351258,6484 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/ambiguous winning effect/stake,135183466,351258,6496 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Draft/stake,1166720427,3099963,11859 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,6488 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/stake,191489761,484291,7641 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/governor,510135973,1283103,11017 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/to next state too late/from Locked/authority,15806303,48240,4585 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/altered output stake datum/from Locked/governor,510135973,1283103,11018 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,4586 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/forget to mint GATs/proposal,411511075,1121605,10706 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/forget to mint GATs/stake,178389602,458680,6929 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/proposal,443845803,1218417,11645 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,7868 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,4812 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs with bad token name/proposal,435762121,1194214,11239 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/mint GATs with bad token name/stake,191489761,484291,7462 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/proposal,435762121,1194214,11412 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/stake,191489761,484291,7635 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/wrong GAT datum/authority,15806303,48240,4579 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/proposal,435762121,1194214,11418 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/stake,191489761,484291,7641 +Agora/Proposal/validator/advancing/with 10 cosigners and 2 effects/illegal/invalid governor output datum/authority,15806303,48240,4585 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/proposal,1326697214,3754088,17404 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Draft to VotingReady/stake,1166720427,3099963,13038 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/proposal,539244672,1453853,12037 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from VotingReady to Locked/stake,135183466,351258,7669 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/proposal,571966165,1548490,13190 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/stake,191489761,484291,8822 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/governor,569890486,1446438,12198 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to next state/from Locked to Finished/authority,15806303,48240,5765 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Draft to Finished/proposal,475718319,1293765,12030 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Draft to Finished/stake,135183466,351258,7664 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/proposal,510950686,1376762,12031 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from VotingReady to Finished/stake,135183466,351258,7665 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Locked to Finished/proposal,512081664,1379166,12031 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/legal/to failed state/from Locked to Finished/stake,135183466,351258,7665 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,1166720427,3099963,13038 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,135183466,351258,7669 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/stake,191489761,484291,8822 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/advance finished proposals/(negative test)/authority,15806303,48240,5765 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/insufficient cosigns/stake,1113969753,2946253,13038 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/insufficient votes/stake,135183466,351258,7665 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/ambiguous winning effect/stake,135183466,351258,7689 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Draft/stake,1166720427,3099963,13040 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from VotingReady/stake,135183466,351258,7669 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/stake,191489761,484291,8822 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/governor,569890486,1446438,12198 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/to next state too late/from Locked/authority,15806303,48240,5765 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/altered output stake datum/from Locked/governor,569890486,1446438,12199 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/altered output stake datum/from Locked/authority,15806303,48240,5766 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/forget to mint GATs/proposal,547715119,1475881,12478 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/forget to mint GATs/stake,178389602,458680,8110 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/proposal,580049847,1572693,13416 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/stake,195037870,491518,9048 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs for wrong validators/authority,17630300,53302,5992 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs with bad token name/proposal,571966165,1548490,13011 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/mint GATs with bad token name/stake,191489761,484291,8643 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/proposal,571966165,1548490,13184 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/stake,191489761,484291,8816 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/wrong GAT datum/authority,15806303,48240,5759 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/proposal,571966165,1548490,13190 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/stake,191489761,484291,8822 +Agora/Proposal/validator/advancing/with 10 cosigners and 5 effects/illegal/invalid governor output datum/authority,15806303,48240,5765 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/stake,130220070,339430,5221 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: retract votes while voting/proposal,236574652,665124,8326 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/stake,133451316,348484,5237 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: retract votes while voting/proposal,250046859,705066,8337 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/stake,130220070,339430,5219 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/creator: remove creator locks when finished/proposal,204366787,584979,8323 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/stake,130220070,339430,5235 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove all locks when finished/proposal,212801044,609883,8335 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/stake,130220070,339430,5225 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Locked/proposal,205682939,588863,8330 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/stake,130220070,339430,5225 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter: unlock after voting/Finished/proposal,205682939,588863,8330 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/stake,133451316,348484,5241 +Agora/Proposal/validator/unlocking/legal/with 1 proposals/voter/creator: remove vote locks when locked/proposal,219686722,630197,8341 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/stake,297011418,750706,7313 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: retract votes while voting/proposal,379215900,1077788,10394 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/stake,313167648,795976,7390 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: retract votes while voting/proposal,444744435,1269042,10446 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/stake,297011418,750706,7303 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/creator: remove creator locks when finished/proposal,312447599,902835,10387 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/stake,297011418,750706,7384 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove all locks when finished/proposal,350836580,1014587,10440 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/stake,297011418,750706,7334 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Locked/proposal,317916859,917911,10415 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/stake,297011418,750706,7334 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter: unlock after voting/Finished/proposal,317916859,917911,10415 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/stake,313167648,795976,7410 +Agora/Proposal/validator/unlocking/legal/with 5 proposals/voter/creator: remove vote locks when locked/proposal,383976970,1110557,10466 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/stake,505500603,1264801,9929 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: retract votes while voting/proposal,557517460,1593618,12980 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/stake,537813063,1355341,10080 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: retract votes while voting/proposal,688116405,1974012,13081 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/stake,505500603,1264801,9909 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/creator: remove creator locks when finished/proposal,447548614,1300155,12968 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/stake,505500603,1264801,10069 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove all locks when finished/proposal,523381000,1520467,13070 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/stake,505500603,1264801,9969 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Locked/proposal,458209259,1329221,13020 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/stake,505500603,1264801,9969 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter: unlock after voting/Finished/proposal,458209259,1329221,13020 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/stake,537813063,1355341,10120 +Agora/Proposal/validator/unlocking/legal/with 10 proposals/voter/creator: remove vote locks when locked/proposal,589339780,1711007,13121 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/stake,1839831387,4555009,26759 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: retract votes while voting/proposal,1698647444,4894930,29599 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/stake,1975543719,4935277,27446 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: retract votes while voting/proposal,2245697013,6485820,30057 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/stake,1839831387,4555009,26674 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/creator: remove creator locks when finished/proposal,1312195110,3843003,29554 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/stake,1839831387,4555009,27385 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove all locks when finished/proposal,1627665288,4758099,29996 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/stake,1839831387,4555009,26927 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Locked/proposal,1356080619,3961605,29767 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/stake,1839831387,4555009,26927 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter: unlock after voting/Finished/proposal,1356080619,3961605,29767 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/stake,1975543719,4935277,27615 +Agora/Proposal/validator/unlocking/legal/with 42 proposals/voter/creator: remove vote locks when locked/proposal,1903661764,5553887,30226 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter , status: Draft/stake",130220070,339430,5221 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter , status: Locked/stake",130220070,339430,5221 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Voter , status: Finished/stake",130220070,339430,5221 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator , status: Draft/stake",125849484,327580,5223 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator , status: Locked/stake",125849484,327580,5223 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Creator , status: Finished/stake",125849484,327580,5223 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both , status: Draft/stake",133451316,348484,5237 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both , status: Locked/stake",133451316,348484,5237 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Both , status: Finished/stake",133451316,348484,5237 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",122618238,318526,5203 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",122618238,318526,5203 +"Agora/Proposal/validator/unlocking/illegal/with 1 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,122618238,318526,5203 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Draft/stake,130220070,339430,5219 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: VotingReady/stake,130220070,339430,5219 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/remove creator too early/status: Locked/stake,130220070,339430,5219 +Agora/Proposal/validator/unlocking/illegal/with 1 proposals/creator: retract votes/stake,130220070,339430,5217 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter , status: Draft/stake",297011418,750706,7313 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter , status: Locked/stake",297011418,750706,7313 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Voter , status: Finished/stake",297011418,750706,7313 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator , status: Draft/stake",290362152,733264,7320 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator , status: Locked/stake",290362152,733264,7320 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Creator , status: Finished/stake",290362152,733264,7320 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both , status: Draft/stake",313167648,795976,7390 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both , status: Locked/stake",313167648,795976,7390 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Both , status: Finished/stake",313167648,795976,7390 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",274205922,687994,7231 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",274205922,687994,7231 +"Agora/Proposal/validator/unlocking/illegal/with 5 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,274205922,687994,7231 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Draft/stake,297011418,750706,7303 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: VotingReady/stake,297011418,750706,7303 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/remove creator too early/status: Locked/stake,297011418,750706,7303 +Agora/Proposal/validator/unlocking/illegal/with 5 proposals/creator: retract votes/stake,297011418,750706,7293 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter , status: Draft/stake",505500603,1264801,9929 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter , status: Locked/stake",505500603,1264801,9929 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Voter , status: Finished/stake",505500603,1264801,9929 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator , status: Draft/stake",496002987,1240369,9940 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator , status: Locked/stake",496002987,1240369,9940 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Creator , status: Finished/stake",496002987,1240369,9940 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both , status: Draft/stake",537813063,1355341,10080 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both , status: Locked/stake",537813063,1355341,10080 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Both , status: Finished/stake",537813063,1355341,10080 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",463690527,1149829,9766 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",463690527,1149829,9766 +"Agora/Proposal/validator/unlocking/illegal/with 10 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,463690527,1149829,9766 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Draft/stake,505500603,1264801,9909 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: VotingReady/stake,505500603,1264801,9909 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/remove creator too early/status: Locked/stake,505500603,1264801,9909 +Agora/Proposal/validator/unlocking/illegal/with 10 proposals/creator: retract votes/stake,505500603,1264801,9888 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter , status: Draft/stake",1839831387,4555009,26759 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter , status: Locked/stake",1839831387,4555009,26759 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Voter , status: Finished/stake",1839831387,4555009,26759 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator , status: Draft/stake",1812104331,4485841,26820 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator , status: Locked/stake",1812104331,4485841,26820 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Creator , status: Finished/stake",1812104331,4485841,26820 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both , status: Draft/stake",1975543719,4935277,27446 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both , status: Locked/stake",1975543719,4935277,27446 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Both , status: Finished/stake",1975543719,4935277,27446 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant , status: Draft/stake",1676391999,4105573,26046 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant , status: Locked/stake",1676391999,4105573,26046 +"Agora/Proposal/validator/unlocking/illegal/with 42 proposals/retract votes while not voting/role: Irrelevant , status: Finished/stake",1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draft retract votes: True/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Draft retract votes: False/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReady retract votes: True/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: VotingReady retract votes: False/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Locked retract votes: True/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Locked retract votes: False/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finished retract votes: True/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/unlock an irrelevant stake/status: Finished retract votes: False/stake,1676391999,4105573,26046 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Draft/stake,1839831387,4555009,26674 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: VotingReady/stake,1839831387,4555009,26674 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/remove creator too early/status: Locked/stake,1839831387,4555009,26674 +Agora/Proposal/validator/unlocking/illegal/with 42 proposals/creator: retract votes/stake,1839831387,4555009,26590 +Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,20570665,54655,725 +Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,32757063,87013,825 +Agora/Treasury/Validator/Positive/Allows for effect changes,31277082,80782,1450 +Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,20570665,54655,725 +Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,32757063,87013,825 +Agora/Governor/policy/totally legal,60002734,167736,2268 +Agora/Governor/validator/mutate/legal,100216324,268169,8154 diff --git a/flake.lock b/flake.lock index 34e3e2c..04af4ee 100644 --- a/flake.lock +++ b/flake.lock @@ -7429,17 +7429,17 @@ "plutarch-quickcheck": "plutarch-quickcheck" }, "locked": { - "lastModified": 1656396683, - "narHash": "sha256-Elk16j7kZcO9U9phqrY915rTEqkPchDZ9QydH+VmiC8=", + "lastModified": 1657959892, + "narHash": "sha256-DKIu0T87UjhaQ96NdibFiIfvnQLN/eJYuLMiPgQmmT8=", "owner": "Liqwid-Labs", "repo": "liqwid-plutarch-extra", - "rev": "6bcd6068593b00adc4a1afd59b127398ea37d770", + "rev": "a951b85d15e7cca1a03dd2a8e36b60fae561d74a", "type": "github" }, "original": { "owner": "Liqwid-Labs", "repo": "liqwid-plutarch-extra", - "rev": "6bcd6068593b00adc4a1afd59b127398ea37d770", + "rev": "a951b85d15e7cca1a03dd2a8e36b60fae561d74a", "type": "github" } }, @@ -10913,11 +10913,11 @@ "plutarch": "plutarch_5" }, "locked": { - "lastModified": 1655751255, - "narHash": "sha256-3Uk1v/V+qm/KBBwBPqzr4X7KiH9DyJ9vhNH2Pw08PkE=", + "lastModified": 1658368717, + "narHash": "sha256-GAneUtaxaJSZLNkIGOTByx/Auuq1g3MhzBhTiqZ13+s=", "owner": "Liqwid-Labs", "repo": "plutarch-context-builder", - "rev": "9e6c81a2e1762a5f8e38cb88b83e2996447e3003", + "rev": "2a2ca72ff310788e531cbbe379ef7b0c4cb42dc9", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index c4849e7..6d915d7 100644 --- a/flake.nix +++ b/flake.nix @@ -17,7 +17,7 @@ "plutarch/haskell-nix/nixpkgs-unstable"; inputs.liqwid-plutarch-extra.url = - "github:Liqwid-Labs/liqwid-plutarch-extra?rev=6bcd6068593b00adc4a1afd59b127398ea37d770"; + "github:Liqwid-Labs/liqwid-plutarch-extra?rev=a951b85d15e7cca1a03dd2a8e36b60fae561d74a"; inputs.plutarch-numeric.url = "github:Liqwid-Labs/plutarch-numeric?ref=main"; inputs.plutarch-safe-money.url =