refactor out ptokenSpent
This commit is contained in:
parent
99cacbf30d
commit
808bf77d14
3 changed files with 70 additions and 44 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue