encode some enum types as integer on chain

This commit is contained in:
Hongrui Fang 2022-06-23 19:24:36 +08:00
parent 6fe5e2b78a
commit 516f6bacda
6 changed files with 140 additions and 117 deletions

View file

@ -45,6 +45,11 @@ import Plutarch.DataRepr (
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.Lift (PConstantDecl, PUnsafeLiftDecl (..))
import Plutarch.SafeMoney (PDiscrete (..))
@ -92,15 +97,27 @@ data GovernorRedeemer
MintGATs
| -- | Allows effects to mutate the parameters.
MutateGovernor
deriving stock (Show, GHC.Generic)
-- | @since 0.1.0
PlutusTx.makeIsDataIndexed
''GovernorRedeemer
[ ('CreateProposal, 0)
, ('MintGATs, 1)
, ('MutateGovernor, 2)
]
deriving stock
( -- | @since 0.1.0
Show
, -- | @since 0.1.0
GHC.Generic
, -- | @since 0.2.0
Enum
, -- | @since 0.2.0
Bounded
)
deriving anyclass
( -- | @since 0.2.0
Generic
)
deriving
( -- | @since 0.1.0
PlutusTx.ToData
, -- | @since 0.1.0
PlutusTx.FromData
)
via (EnumIsData GovernorRedeemer)
{- | Parameters for creating Governor scripts.
@ -172,10 +189,8 @@ deriving via PAsData (PIsDataReprInstances PGovernorDatum) instance PTryFrom PDa
@since 0.1.0
-}
data PGovernorRedeemer (s :: S)
= PCreateProposal (Term s (PDataRecord '[]))
| PMintGATs (Term s (PDataRecord '[]))
| PMutateGovernor (Term s (PDataRecord '[]))
newtype PGovernorRedeemer (s :: S)
= PGovernorRedeemer (Term s PInteger)
deriving stock
( -- | @since 0.1.0
GHC.Generic
@ -184,26 +199,19 @@ data PGovernorRedeemer (s :: S)
( -- | @since 0.1.0
Generic
)
deriving anyclass
( -- | @since 0.1.0
PIsDataRepr
)
deriving
( -- | @since 0.1.0
PlutusType
, -- | @since 0.1.0
PIsData
)
via PIsDataReprInstances PGovernorRedeemer
via (DerivePNewtype' PGovernorRedeemer)
-- | @since 0.1.0
instance PUnsafeLiftDecl PGovernorRedeemer where type PLifted PGovernorRedeemer = GovernorRedeemer
-- | @since 0.1.0
deriving via (DerivePConstantViaData GovernorRedeemer PGovernorRedeemer) instance (PConstantDecl GovernorRedeemer)
-- | @since 0.1.0
deriving via PAsData (PIsDataReprInstances PGovernorRedeemer) instance PTryFrom PData (PAsData PGovernorRedeemer)
deriving via (DerivePConstantViaEnum GovernorRedeemer PGovernorRedeemer) instance (PConstantDecl GovernorRedeemer)
--------------------------------------------------------------------------------

View file

@ -39,18 +39,17 @@ import Agora.AuthorityToken (
)
import Agora.Governor (
Governor (gstOutRef, gtClassRef, maximumCosigners),
GovernorRedeemer (..),
PGovernorDatum (PGovernorDatum),
PGovernorRedeemer (PCreateProposal, PMintGATs, PMutateGovernor),
governorDatumValid,
pgetNextProposalId,
)
import Agora.Proposal (
PProposalDatum (..),
PProposalId (..),
PProposalStatus (PFinished),
PResultTag,
Proposal (..),
ProposalStatus (Draft, Locked),
ProposalStatus (Draft, Finished, Locked),
pemptyVotesFor,
pneutralOption,
proposalDatumValid,
@ -105,20 +104,20 @@ import Plutarch.Api.V1.AssetClass (
passetClass,
passetClassValueOf,
)
import Plutarch.Api.V1.ScriptContext (pfindTxInByTxOutRef, pisUTXOSpent, ptryFindDatum, ptxSignedBy, pvalueSpent)
import "liqwid-plutarch-extra" Plutarch.Api.V1.Value (psymbolValueOf)
import Plutarch.Extra.IsData (pmatchEnumFromData)
import Plutarch.Extra.Map (
pkeys,
plookup,
plookup',
)
import Plutarch.Extra.Maybe (pisDJust)
import Plutarch.Extra.TermCont (pguardC, pletC, pletFieldsC, pmatchC, ptryFromC)
import Plutarch.SafeMoney (PDiscrete (..), pvalueDiscrete')
import Plutarch.TryFrom ()
--------------------------------------------------------------------------------
import Plutarch.Api.V1.ScriptContext (pfindTxInByTxOutRef, pisUTXOSpent, ptryFindDatum, ptxSignedBy, pvalueSpent)
import "liqwid-plutarch-extra" Plutarch.Api.V1.Value (psymbolValueOf)
import Plutarch.Extra.Maybe (pisDJust)
import Plutarch.Extra.TermCont
import PlutusLedgerApi.V1 (
CurrencySymbol (..),
MintingPolicy,
@ -280,7 +279,6 @@ governorPolicy gov =
governorValidator :: Governor -> ClosedTerm PValidator
governorValidator gov =
plam $ \datum' redeemer' ctx' -> unTermCont $ do
(pfromData -> redeemer, _) <- ptryFromC redeemer'
ctxF <- pletFieldsC @'["txInfo", "purpose"] ctx'
txInfo' <- pletC $ pfromData $ ctxF.txInfo
@ -330,8 +328,8 @@ governorValidator gov =
pguardC "New datum is not valid" $ governorDatumValid # newGovernorDatum
pure $
pmatch redeemer $ \case
PCreateProposal _ -> unTermCont $ do
pmatchEnumFromData redeemer' $ \case
Just CreateProposal -> unTermCont $ do
-- Check that the transaction advances proposal id.
let expectedNextProposalId = pgetNextProposalId # oldGovernorDatumF.nextProposalId
@ -516,7 +514,7 @@ governorValidator gov =
--------------------------------------------------------------------------
PMintGATs _ -> unTermCont $ do
Just MintGATs -> unTermCont $ do
pguardC "Governor state should not be changed" $ newGovernorDatum #== oldGovernorDatum
-- Filter out proposal inputs and ouputs using PST and the address of proposal validator.
@ -583,7 +581,7 @@ governorValidator gov =
PProposalDatum
( #proposalId .= proposalInputDatumF.proposalId
.& #effects .= proposalInputDatumF.effects
.& #status .= pdata (pcon $ PFinished pdnil)
.& #status .= pconstantData Finished
.& #cosigners .= proposalInputDatumF.cosigners
.& #thresholds .= proposalInputDatumF.thresholds
.& #votes .= proposalInputDatumF.votes
@ -667,9 +665,12 @@ governorValidator gov =
--------------------------------------------------------------------------
PMutateGovernor _ -> unTermCont $ do
Just MutateGovernor -> unTermCont $ do
-- Check that a GAT is burnt.
pure $ popaque $ singleAuthorityTokenBurned patSymbol ctxF.txInfo txInfoF.mint
--------------------------------------------------------------------------
Nothing -> ptraceError "Unknown redeemer"
where
-- Get th amount of governance tokens in a value.
pgtValueOf :: Term s (PValue _ _ :--> PDiscrete GTTag)

View file

@ -51,9 +51,14 @@ import Plutarch.Api.V1 (
PValidatorHash,
)
import Plutarch.DataRepr (DerivePConstantViaData (..), PDataFields, PIsDataReprInstances (..))
import Plutarch.Extra.IsData (
DerivePConstantViaEnum (..),
EnumIsData (..),
)
import Plutarch.Extra.List (pnotNull)
import Plutarch.Extra.Map qualified as PM
import Plutarch.Extra.Map.Unsorted qualified as PUM
import Plutarch.Extra.Other (DerivePNewtype' (..))
import Plutarch.Extra.TermCont (pguardC, pletC, pletFieldsC)
import Plutarch.Lift (
DerivePConstantViaNewtype (..),
@ -173,10 +178,24 @@ data ProposalStatus
Show
, -- | @since 0.1.0
GHC.Generic
, -- | @since 0.2.0
Enum
, -- | @since 0.2.0
Bounded
)
-- | @since 0.1.0
PlutusTx.makeIsDataIndexed ''ProposalStatus [('Draft, 0), ('VotingReady, 1), ('Locked, 2), ('Finished, 3)]
deriving anyclass
( -- | @since 0.2.0
Generic
)
deriving
( -- | @since 0.1.0
PlutusTx.FromData
, -- | @since 0.1.0
PlutusTx.ToData
, -- | @since 0.1.0
PlutusTx.UnsafeFromData
)
via (EnumIsData ProposalStatus)
{- | The threshold values for various state transitions to happen.
This data is stored centrally (in the 'Agora.Governor.Governor') and copied over
@ -433,13 +452,7 @@ deriving via
@since 0.1.0
-}
data PProposalStatus (s :: S)
= -- TODO: 'PProposalStatus' ought te be encoded as 'PInteger'.
-- e.g. like Tilde used 'pmatchEnum'.
PDraft (Term s (PDataRecord '[]))
| PVotingReady (Term s (PDataRecord '[]))
| PLocked (Term s (PDataRecord '[]))
| PFinished (Term s (PDataRecord '[]))
newtype PProposalStatus (s :: S) = PProposalStatus (Term s PInteger)
deriving stock
( -- | @since 0.1.0
GHC.Generic
@ -448,10 +461,6 @@ data PProposalStatus (s :: S)
( -- | @since 0.1.0
Generic
)
deriving anyclass
( -- | @since 0.1.0
PIsDataRepr
)
deriving
( -- | @since 0.1.0
PlutusType
@ -460,16 +469,16 @@ data PProposalStatus (s :: S)
, -- | @since 0.1.0
PEq
)
via PIsDataReprInstances PProposalStatus
via (DerivePNewtype' PProposalStatus)
-- | @since 0.1.0
instance PUnsafeLiftDecl PProposalStatus where type PLifted PProposalStatus = ProposalStatus
-- | @since 0.1.0
deriving via PAsData (PIsDataReprInstances PProposalStatus) instance PTryFrom PData (PAsData PProposalStatus)
deriving via PAsData (DerivePNewtype' PProposalStatus) instance PTryFrom PData (PAsData PProposalStatus)
-- | @since 0.1.0
deriving via (DerivePConstantViaData ProposalStatus PProposalStatus) instance (PConstantDecl ProposalStatus)
deriving via (DerivePConstantViaEnum ProposalStatus PProposalStatus) instance (PConstantDecl ProposalStatus)
{- | Plutarch-level version of 'ProposalThresholds'.

View file

@ -13,7 +13,6 @@ module Agora.Proposal.Scripts (
import Agora.Proposal (
PProposalDatum (PProposalDatum),
PProposalRedeemer (..),
PProposalStatus (..),
PProposalVotes (PProposalVotes),
Proposal (governorSTAssetClass, stakeSTAssetClass),
ProposalStatus (..),
@ -55,6 +54,7 @@ import Plutarch.Api.V1.ScriptContext (
)
import "liqwid-plutarch-extra" Plutarch.Api.V1.Value (psymbolValueOf)
import Plutarch.Extra.Comonad (pextract)
import Plutarch.Extra.IsData (pmatchEnum)
import Plutarch.Extra.List (pisUniqBy)
import Plutarch.Extra.Map (plookup, pupdate)
import Plutarch.Extra.Maybe (pisJust)
@ -510,19 +510,21 @@ proposalValidator proposal =
inLockedPeriod <- pletC $ isLockingPeriod # proposalF.timingConfig # proposalF.startingTime # currentTime
inExecutionPeriod <- pletC $ isExecutionPeriod # proposalF.timingConfig # proposalF.startingTime # currentTime
proposalStatus <- pletC $ pto $ pfromData proposalF.status
-- Check the timings.
let isFinished = proposalF.status #== pconstantData Finished
notTooLate = pmatch (pfromData proposalF.status) $ \case
PDraft _ -> inDraftPeriod
notTooLate = pmatchEnum proposalStatus $ \case
Draft -> inDraftPeriod
-- Can only advance after the voting period is over.
PVotingReady _ -> inLockedPeriod
PLocked _ -> inExecutionPeriod
VotingReady -> inLockedPeriod
Locked -> inExecutionPeriod
_ -> pconstant False
notTooEarly = pmatch (pfromData proposalF.status) $ \case
PVotingReady _ -> pnot # inVotingPeriod
PLocked _ -> pnot # inLockedPeriod
notTooEarly = pmatchEnum (pto $ pfromData proposalF.status) $ \case
VotingReady -> pnot # inVotingPeriod
Locked -> pnot # inLockedPeriod
_ -> pconstant True
pguardC "Cannot advance ahead of time" notTooEarly
@ -534,8 +536,8 @@ proposalValidator proposal =
pif
notTooLate
-- On time: advance to next status.
( pmatch (pfromData proposalF.status) $ \case
PDraft _ -> unTermCont $ do
( pmatchEnum proposalStatus $ \case
Draft -> unTermCont $ do
-- TODO: Perform other necessary checks.
-- 'Draft' -> 'VotingReady'
@ -543,7 +545,7 @@ proposalValidator proposal =
proposalOutStatus #== pconstantData VotingReady
pure $ popaque (pconstant ())
PVotingReady _ -> unTermCont $ do
VotingReady -> unTermCont $ do
-- 'VotingReady' -> 'Locked'
pguardC "Proposal status set to Locked" $
proposalOutStatus #== pconstantData Locked
@ -554,7 +556,7 @@ proposalValidator proposal =
$ pfromData thresholdsF.execute
pure $ popaque (pconstant ())
PLocked _ -> unTermCont $ do
Locked -> unTermCont $ do
-- 'Locked' -> 'Finished'
pguardC "Proposal status set to Finished" $
proposalOutStatus #== pconstantData Finished

View file

@ -12,15 +12,13 @@ module Agora.Treasury (module Agora.Treasury) where
import Agora.AuthorityToken (singleAuthorityTokenBurned)
import GHC.Generics qualified as GHC
import Generics.SOP (Generic, I (I))
import Generics.SOP (Generic)
import Plutarch.Api.V1 (PValidator)
import Plutarch.Api.V1.Contexts (PScriptPurpose (PMinting))
import "plutarch" Plutarch.Api.V1.Value (PValue)
import Plutarch.DataRepr (
DerivePConstantViaData (..),
PIsDataReprInstances (PIsDataReprInstances),
)
import Plutarch.Extra.TermCont (pguardC, pletC, pletFieldsC, pmatchC, ptryFromC)
import Plutarch.Extra.IsData (DerivePConstantViaEnum (..), EnumIsData (..), pmatchEnumFromData)
import Plutarch.Extra.Other (DerivePNewtype' (..))
import Plutarch.Extra.TermCont (pguardC, pletC, pletFieldsC, pmatchC)
import Plutarch.Lift (PConstantDecl (..), PLifted (..), PUnsafeLiftDecl)
import Plutarch.TryFrom ()
import PlutusLedgerApi.V1.Value (CurrencySymbol)
@ -40,13 +38,22 @@ data TreasuryRedeemer
Show
, -- | @since 0.1.0
GHC.Generic
, -- | @since 0.2.0
Enum
, -- | @since 0.2.0
Bounded
)
-- | @since 0.1.0
PlutusTx.makeIsDataIndexed
''TreasuryRedeemer
[ ('SpendTreasuryGAT, 0)
]
deriving anyclass
( -- | @since 0.2.0
Generic
)
deriving
( -- | @since 0.1.0
PlutusTx.ToData
, -- | @since 0.1.0
PlutusTx.FromData
)
via (EnumIsData TreasuryRedeemer)
--------------------------------------------------------------------------------
@ -56,9 +63,7 @@ PlutusTx.makeIsDataIndexed
@since 0.1.0
-}
newtype PTreasuryRedeemer (s :: S)
= -- | Alters treasury parameters, subject to the burning of a
-- governance authority token.
PSpendTreasuryGAT (Term s (PDataRecord '[]))
= PTreasuryRedeemer (Term s PInteger)
deriving stock
( -- | @since 0.1.0
GHC.Generic
@ -66,8 +71,6 @@ newtype PTreasuryRedeemer (s :: S)
deriving anyclass
( -- | @since 0.1.0
Generic
, -- | @since 0.1.0
PIsDataRepr
)
deriving
( -- | @since 0.1.0
@ -75,13 +78,7 @@ newtype PTreasuryRedeemer (s :: S)
, -- | @since 0.1.0
PIsData
)
via PIsDataReprInstances PTreasuryRedeemer
-- | @since 0.1.0
deriving via
PAsData (PIsDataReprInstances PTreasuryRedeemer)
instance
PTryFrom PData (PAsData PTreasuryRedeemer)
via (DerivePNewtype' PTreasuryRedeemer)
-- | @since 0.1.0
instance PUnsafeLiftDecl PTreasuryRedeemer where
@ -89,7 +86,7 @@ instance PUnsafeLiftDecl PTreasuryRedeemer where
-- | @since 0.1.0
deriving via
(DerivePConstantViaData TreasuryRedeemer PTreasuryRedeemer)
(DerivePConstantViaEnum TreasuryRedeemer PTreasuryRedeemer)
instance
(PConstantDecl TreasuryRedeemer)
@ -105,8 +102,6 @@ treasuryValidator ::
CurrencySymbol ->
ClosedTerm PValidator
treasuryValidator gatCs' = plam $ \_datum redeemer ctx' -> unTermCont $ do
(treasuryRedeemer, _) <- ptryFromC redeemer
-- plet required fields from script context.
ctx <- pletFieldsC @["txInfo", "purpose"] ctx'
@ -114,7 +109,15 @@ treasuryValidator gatCs' = plam $ \_datum redeemer ctx' -> unTermCont $ do
PMinting _ <- pmatchC ctx.purpose
-- Ensure redeemer type is valid.
PSpendTreasuryGAT _ <- pmatchC $ pfromData treasuryRedeemer
let redeemerValid =
pmatchEnumFromData
redeemer
( \case
Just SpendTreasuryGAT -> pconstant True
_ -> pconstant False
)
pguardC "Redeemer should be SpendTreasuryGAT" redeemerValid
-- Get the minted value from txInfo.
txInfo' <- pletC ctx.txInfo