refactor out ptokenSpent

This commit is contained in:
Emily Martins 2022-04-13 16:39:08 +02:00
parent 99cacbf30d
commit 808bf77d14
3 changed files with 70 additions and 44 deletions

View file

@ -18,16 +18,14 @@ import Plutarch.Api.V1 (
PCurrencySymbol (..), PCurrencySymbol (..),
PScriptContext (..), PScriptContext (..),
PScriptPurpose (..), PScriptPurpose (..),
PTxInInfo (..),
PTxInfo (..), PTxInfo (..),
PTxOut (..), PTxOut (..),
) )
import Plutarch.Api.V1.AssocMap (PMap (PMap)) import Plutarch.Api.V1.AssocMap (PMap (PMap))
import Plutarch.Api.V1.Value (PValue (PValue)) import Plutarch.Api.V1.Value (PValue (PValue))
import Plutarch.Builtin (pforgetData) import Plutarch.Builtin (pforgetData)
import Plutarch.List (pfoldr')
import Plutarch.Monadic qualified as P import Plutarch.Monadic qualified as P
import Plutus.V1.Ledger.Value (AssetClass) import Plutus.V1.Ledger.Value (AssetClass (AssetClass))
import Prelude import Prelude
@ -36,11 +34,11 @@ import Prelude
import Agora.Utils ( import Agora.Utils (
allOutputs, allOutputs,
passert, passert,
passetClassValueOf,
passetClassValueOf',
plookup, plookup,
psymbolValueOf, psymbolValueOf,
ptokenSpent,
) )
import Plutarch.Api.V1.Extra (passetClass, passetClassValueOf)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -132,26 +130,19 @@ authorityTokenPolicy params =
PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo
txInfo <- pletFields @'["inputs", "mint"] txInfo' txInfo <- pletFields @'["inputs", "mint"] txInfo'
let inputs = txInfo.inputs let inputs = txInfo.inputs
let authorityTokenInputs = mintedValue = pfromData txInfo.mint
pfoldr' @PBuiltinList AssetClass (govCs, govTn) = params.authority
( \txInInfo' acc -> P.do govAc = passetClass # pconstant govCs # pconstant govTn
PTxInInfo txInInfo <- pmatch (pfromData txInInfo') govTokenSpent = ptokenSpent # govAc # inputs
PTxOut txOut' <- pmatch $ pfromData $ pfield @"resolved" # txInInfo
txOut <- pletFields @'["value"] txOut'
let txOutValue = pfromData txOut.value
passetClassValueOf' params.authority # txOutValue + acc
)
# 0
# inputs
let mintedValue = pfromData txInfo.mint
let tokenMoved = 0 #< authorityTokenInputs
PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose
let ownSymbol = pfromData $ pfield @"_0" # ownSymbol' let ownSymbol = pfromData $ pfield @"_0" # ownSymbol'
let mintedATs = passetClassValueOf # ownSymbol # pconstant "" # mintedValue mintedATs = passetClassValueOf # mintedValue # (passetClass # ownSymbol # pconstant "")
pif pif
(0 #< mintedATs) (0 #< mintedATs)
( P.do ( P.do
passert "Parent token did not move in minting GATs" tokenMoved passert "Parent token did not move in minting GATs" govTokenSpent
passert "All outputs only emit valid GATs" $ passert "All outputs only emit valid GATs" $
allOutputs @PUnit # pfromData ctx.txInfo #$ plam $ \txOut _value _address _datum -> allOutputs @PUnit # pfromData ctx.txInfo #$ plam $ \txOut _value _address _datum ->
authorityTokensValidIn authorityTokensValidIn

View file

@ -1,5 +1,4 @@
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -Wno-unused-matches #-}
{- | {- |
Module : Agora.Proposal Module : Agora.Proposal
@ -39,6 +38,9 @@ import Plutarch.Api.V1 (
PMap, PMap,
PMintingPolicy, PMintingPolicy,
PPubKeyHash, PPubKeyHash,
PScriptContext (PScriptContext),
PScriptPurpose (PMinting, PSpending),
PTxInfo (PTxInfo),
PValidator, PValidator,
PValidatorHash, PValidatorHash,
) )
@ -54,14 +56,15 @@ import PlutusTx.AssocMap qualified as AssocMap
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Agora.SafeMoney (GTTag) import Agora.SafeMoney (GTTag)
import Agora.Utils (pnotNull) import Agora.Utils (passert, pnotNull, ptokenSpent)
import Plutarch (popaque) import Plutarch (popaque)
import Plutarch.Api.V1.Extra (passetClass, passetClassValueOf)
import Plutarch.Builtin (PBuiltinMap) import Plutarch.Builtin (PBuiltinMap)
import Plutarch.Lift (DerivePConstantViaNewtype (..), PUnsafeLiftDecl (..)) import Plutarch.Lift (DerivePConstantViaNewtype (..), PUnsafeLiftDecl (..))
import Plutarch.Monadic qualified as P import Plutarch.Monadic qualified as P
import Plutarch.SafeMoney (PDiscrete, Tagged) import Plutarch.SafeMoney (PDiscrete, Tagged)
import Plutarch.Unsafe (punsafeCoerce) import Plutarch.Unsafe (punsafeCoerce)
import Plutus.V1.Ledger.Value (AssetClass) import Plutus.V1.Ledger.Value (AssetClass (AssetClass))
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Haskell-land -- Haskell-land
@ -282,17 +285,46 @@ deriving via (DerivePConstantViaData ProposalDatum PProposalDatum) instance (PCo
{- | Policy for Proposals. {- | Policy for Proposals.
This needs to perform two checks: This needs to perform two checks:
- Governor is happy with mint. - Governor is happy with mint.
- Datum is valid - Exactly 1 token is minted.
NOTE: The governor needs to check that the datum is correct
and sent to the right address.
-} -}
proposalPolicy :: Proposal -> ClosedTerm PMintingPolicy proposalPolicy :: Proposal -> ClosedTerm PMintingPolicy
proposalPolicy _ = proposalPolicy proposal =
plam $ \_redeemer _ctx' -> P.do plam $ \_redeemer ctx' -> P.do
PScriptContext ctx' <- pmatch ctx'
ctx <- pletFields @'["txInfo", "purpose"] ctx'
PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo
txInfo <- pletFields @'["inputs", "mint"] txInfo'
PMinting _ownSymbol <- pmatch $ pfromData ctx.purpose
let inputs = txInfo.inputs
mintedValue = pfromData txInfo.mint
AssetClass (govCs, govTn) = proposal.governorSTAssetClass
PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose
let mintedProposalST = passetClassValueOf # mintedValue # (passetClass # (pfield @"_0" # ownSymbol') # pconstant "")
passert "Governance state-thread token must move" $
ptokenSpent
# (passetClass # pconstant govCs # pconstant govTn)
# inputs
passert "Minted exactly one proposal ST" $
mintedProposalST #== 1
popaque (pconstant ()) popaque (pconstant ())
-- | Validator for Proposals. -- | Validator for Proposals.
proposalValidator :: Proposal -> ClosedTerm PValidator proposalValidator :: Proposal -> ClosedTerm PValidator
proposalValidator _ = proposalValidator _ =
plam $ \_datum _redeemer _ctx' -> P.do plam $ \_datum _redeemer ctx' -> P.do
PScriptContext ctx' <- pmatch ctx'
ctx <- pletFields @'["txInfo", "purpose"] ctx'
PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo
_txInfo <- pletFields @'["inputs", "mint"] txInfo'
PSpending _txOutRef <- pmatch $ pfromData ctx.purpose
popaque (pconstant ()) popaque (pconstant ())
{- | Check for various invariants a proposal must uphold. {- | Check for various invariants a proposal must uphold.

View file

@ -17,8 +17,6 @@ module Agora.Utils (
plookup, plookup,
pfromMaybe, pfromMaybe,
psymbolValueOf, psymbolValueOf,
passetClassValueOf,
passetClassValueOf',
pgeqByClass, pgeqByClass,
pgeqBySymbol, pgeqBySymbol,
pgeqByClass', pgeqByClass',
@ -27,6 +25,7 @@ module Agora.Utils (
pfindMap, pfindMap,
pnotNull, pnotNull,
pisJust, pisJust,
ptokenSpent,
-- * Functions which should (probably) not be upstreamed -- * Functions which should (probably) not be upstreamed
anyOutput, anyOutput,
@ -63,6 +62,7 @@ import Plutarch.Api.V1 (
PValue, PValue,
) )
import Plutarch.Api.V1.AssocMap (PMap (PMap)) import Plutarch.Api.V1.AssocMap (PMap (PMap))
import Plutarch.Api.V1.Extra (PAssetClass, passetClassValueOf, pvalueOf)
import Plutarch.Api.V1.Value (PValue (PValue)) import Plutarch.Api.V1.Value (PValue (PValue))
import Plutarch.Builtin (ppairDataBuiltin) import Plutarch.Builtin (ppairDataBuiltin)
import Plutarch.Internal (punsafeCoerce) import Plutarch.Internal (punsafeCoerce)
@ -183,30 +183,17 @@ psymbolValueOf =
PMap m <- pmatch (pfromData m') PMap m <- pmatch (pfromData m')
pfoldr # plam (\x v -> pfromData (psndBuiltin # x) + v) # 0 # m pfoldr # plam (\x v -> pfromData (psndBuiltin # x) + v) # 0 # m
-- | Extract amount from PValue belonging to a Plutarch-level asset class.
passetClassValueOf ::
Term s (PCurrencySymbol :--> PTokenName :--> PValue :--> PInteger)
passetClassValueOf =
phoistAcyclic $
plam $ \sym token value'' -> P.do
PValue value' <- pmatch value''
PMap value <- pmatch value'
m' <- pexpectJust 0 (plookup # pdata sym # value)
PMap m <- pmatch (pfromData m')
v <- pexpectJust 0 (plookup # pdata token # m)
pfromData v
-- | Extract amount from PValue belonging to a Haskell-level AssetClass. -- | Extract amount from PValue belonging to a Haskell-level AssetClass.
passetClassValueOf' :: AssetClass -> Term s (PValue :--> PInteger) passetClassValueOf' :: AssetClass -> Term s (PValue :--> PInteger)
passetClassValueOf' (AssetClass (sym, token)) = passetClassValueOf' (AssetClass (sym, token)) =
passetClassValueOf # pconstant sym # pconstant token phoistAcyclic $ plam $ \value -> pvalueOf # value # pconstant sym # pconstant token
-- | Return '>=' on two values comparing by only a particular AssetClass. -- | Return '>=' on two values comparing by only a particular AssetClass.
pgeqByClass :: Term s (PCurrencySymbol :--> PTokenName :--> PValue :--> PValue :--> PBool) pgeqByClass :: Term s (PCurrencySymbol :--> PTokenName :--> PValue :--> PValue :--> PBool)
pgeqByClass = pgeqByClass =
phoistAcyclic $ phoistAcyclic $
plam $ \cs tn a b -> plam $ \cs tn a b ->
passetClassValueOf # cs # tn # b #<= passetClassValueOf # cs # tn # a pvalueOf # b # cs # tn #<= pvalueOf # a # cs # tn
-- | Return '>=' on two values comparing by only a particular CurrencySymbol. -- | Return '>=' on two values comparing by only a particular CurrencySymbol.
pgeqBySymbol :: Term s (PCurrencySymbol :--> PValue :--> PValue :--> PBool) pgeqBySymbol :: Term s (PCurrencySymbol :--> PValue :--> PValue :--> PBool)
@ -421,3 +408,19 @@ findTxOutDatum = phoistAcyclic $
case datumHash' of case datumHash' of
PDJust ((pfield @"_0" #) -> datumHash) -> pfindDatum # datumHash # info PDJust ((pfield @"_0" #) -> datumHash) -> pfindDatum # datumHash # info
_ -> pcon PNothing _ -> pcon PNothing
-- | Check if a particular asset class has been spent in the input list.
ptokenSpent :: forall {s :: S}. Term s (PAssetClass :--> PBuiltinList (PAsData PTxInInfo) :--> PBool)
ptokenSpent =
plam $ \tokenClass inputs ->
0
#< pfoldr @PBuiltinList
# ( plam $ \txInInfo' acc -> P.do
PTxInInfo txInInfo <- pmatch (pfromData txInInfo')
PTxOut txOut' <- pmatch $ pfromData $ pfield @"resolved" # txInInfo
txOut <- pletFields @'["value"] txOut'
let txOutValue = pfromData txOut.value
acc + passetClassValueOf # txOutValue # tokenClass
)
# 0
# inputs