diff --git a/agora/Agora/Governor.hs b/agora/Agora/Governor.hs index 3beafe5..8cf49f9 100644 --- a/agora/Agora/Governor.hs +++ b/agora/Agora/Governor.hs @@ -20,6 +20,7 @@ module Agora.Governor ( -- * Utilities pgetNextProposalId, getNextProposalId, + governorDatumValid, ) where -------------------------------------------------------------------------------- @@ -32,7 +33,7 @@ import Generics.SOP (Generic, I (I)) import Agora.Proposal ( PProposalId (..), - PProposalThresholds, + PProposalThresholds (..), ProposalId (ProposalId), ProposalThresholds, ) @@ -46,7 +47,8 @@ import Plutarch.DataRepr ( PIsDataReprInstances (PIsDataReprInstances), ) import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (..)) -import Plutarch.SafeMoney (Tagged (..)) +import Plutarch.Monadic qualified as P +import Plutarch.SafeMoney (Tagged (..), puntag) import Plutarch.TryFrom (PTryFrom (..)) import Plutarch.Unsafe (punsafeCoerce) @@ -161,3 +163,25 @@ pgetNextProposalId = phoistAcyclic $ plam $ \(pto -> pid) -> pcon $ PProposalId -- | Get next proposal id. getNextProposalId :: ProposalId -> ProposalId getNextProposalId (ProposalId pid) = ProposalId $ pid + 1 + +-------------------------------------------------------------------------------- + +governorDatumValid :: Term s (PGovernorDatum :--> PBool) +governorDatumValid = phoistAcyclic $ + plam $ \datum -> P.do + thresholds <- + pletFields @'["execute", "draft", "vote"] $ + pfield @"proposalThresholds" # datum + + execute <- plet $ puntag thresholds.execute + draft <- plet $ puntag thresholds.draft + vote <- plet $ puntag thresholds.vote + + foldr1 + (#&&) + [ ptraceIfFalse "Execute threshold larger than 0" $ 0 #<= execute + , ptraceIfFalse "Draft threshold larger than 0" $ 0 #<= draft + , ptraceIfFalse "Vote threshold larger than 0" $ 0 #<= vote + , ptraceIfFalse "Draft threshold larger than vote threshold" $ draft #<= vote + , ptraceIfFalse "Execute threshold larger than vote threshold" $ vote #< execute + ] diff --git a/agora/Agora/Governor/Scripts.hs b/agora/Agora/Governor/Scripts.hs index 63601dc..b131057 100644 --- a/agora/Agora/Governor/Scripts.hs +++ b/agora/Agora/Governor/Scripts.hs @@ -42,6 +42,7 @@ import Agora.Governor ( Governor (gstOutRef, gtClassRef, maximumCosigners), PGovernorDatum (PGovernorDatum), PGovernorRedeemer (PCreateProposal, PMintGATs, PMutateGovernor), + governorDatumValid, pgetNextProposalId, ) import Agora.Proposal ( @@ -157,6 +158,7 @@ import Plutus.V1.Ledger.Value ( - The UTXO referenced in the parameter is spent in the transaction. - Exactly one GST is minted. - Ensure the token name is empty. + - Said UTXO should carry a valid 'Agora.Governor.GovernorDatum'. NOTE: It's user's responsibility to make sure the token is sent to the corresponding governor validator. We /can't/ really check this in the policy, otherwise we create a cyclic reference issue. @@ -170,7 +172,7 @@ governorPolicy gov = let ownAssetClass = passetClass # ownSymbol # pconstant "" txInfo = pfromData $ pfield @"txInfo" # ctx' - txInfoF <- pletFields @'["mint", "inputs"] txInfo + txInfoF <- pletFields @'["mint", "inputs", "outputs", "datums"] txInfo passert "Referenced utxo should be spent" $ pisUTXOSpent # oref # txInfoF.inputs @@ -179,7 +181,21 @@ governorPolicy gov = psymbolValueOf # ownSymbol # txInfoF.mint #== 1 #&& passetClassValueOf # txInfoF.mint # ownAssetClass #== 1 - popaque (pconstant ()) + govOutput <- + plet $ + mustBePJust + # "Governor output not found" + #$ pfind + # plam + ( \((pfield @"value" #) . pfromData -> value) -> + psymbolValueOf # ownSymbol # value #== 1 + ) + # pfromData txInfoF.outputs + + let datumHash = pfield @"datumHash" # pfromData govOutput + datum = mustFindDatum' @PGovernorDatum # datumHash # txInfoF.datums + + popaque $ governorDatumValid # datum {- | Validator for Governors.