simplify some PTxInfo functions

This commit is contained in:
Emily Martins 2022-04-19 22:20:17 +02:00
parent 83230e0948
commit 832e15fc16
4 changed files with 113 additions and 73 deletions

View file

@ -60,7 +60,16 @@ import PlutusTx.AssocMap qualified as AssocMap
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Agora.SafeMoney (GTTag) import Agora.SafeMoney (GTTag)
import Agora.Utils (passert, pnotNull, psymbolValueOf, ptokenSpent, pvalueSpent) import Agora.Utils (
anyOutput,
findTxOutByTxOutRef,
passert,
pnotNull,
psymbolValueOf,
ptokenSpent,
ptxSignedBy,
pvalueSpent,
)
import Control.Arrow (first) import Control.Arrow (first)
import Plutarch.Api.V1.Extra (passetClass, passetClassValueOf) import Plutarch.Api.V1.Extra (passetClass, passetClassValueOf)
import Plutarch.Builtin (PBuiltinMap) import Plutarch.Builtin (PBuiltinMap)
@ -427,17 +436,25 @@ proposalValidator proposal =
plam $ \datum redeemer ctx' -> P.do plam $ \datum redeemer ctx' -> P.do
PScriptContext ctx' <- pmatch ctx' PScriptContext ctx' <- pmatch ctx'
ctx <- pletFields @'["txInfo", "purpose"] ctx' ctx <- pletFields @'["txInfo", "purpose"] ctx'
PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo txInfo <- plet $ pfromData ctx.txInfo
_txInfo <- pletFields @'["inputs", "mint"] txInfo' PTxInfo txInfo' <- pmatch $ txInfo
PSpending _txOutRef <- pmatch $ pfromData ctx.purpose txInfoF <- pletFields @'["inputs", "mint"] txInfo'
PSpending ((pfield @"_0" #) -> txOutRef) <- pmatch $ pfromData ctx.purpose
let _proposalDatum' :: Term _ PProposalDatum PJust txOut <- pmatch $ findTxOutByTxOutRef # txOutRef # txInfoF.inputs
_proposalDatum' = pfromData $ punsafeCoerce datum txOutF <- pletFields @'["address"] $ txOut
let proposalDatum :: Term _ PProposalDatum
proposalDatum = pfromData $ punsafeCoerce datum
proposalRedeemer :: Term _ PProposalRedeemer proposalRedeemer :: Term _ PProposalRedeemer
proposalRedeemer = pfromData $ punsafeCoerce redeemer proposalRedeemer = pfromData $ punsafeCoerce redeemer
proposalF <- pletFields @'["cosigners"] proposalDatum
ownAddress <- plet $ txOutF.address
stCurrencySymbol <- plet $ pconstant $ mintingPolicySymbol $ mkMintingPolicy (proposalPolicy proposal) stCurrencySymbol <- plet $ pconstant $ mintingPolicySymbol $ mkMintingPolicy (proposalPolicy proposal)
spentST <- plet $ psymbolValueOf # stCurrencySymbol #$ pvalueSpent # ctx.txInfo spentST <- plet $ psymbolValueOf # stCurrencySymbol #$ pvalueSpent # txInfoF.inputs
pmatch proposalRedeemer $ \case pmatch proposalRedeemer $ \case
PVote _r -> P.do PVote _r -> P.do
@ -446,10 +463,33 @@ proposalValidator proposal =
popaque (pconstant ()) popaque (pconstant ())
-------------------------------------------------------------------------- --------------------------------------------------------------------------
PCosign _r -> P.do PCosign r -> P.do
newSigs <- plet $ pfield @"newCosigners" # r
passert "ST at inputs must be 1" $ passert "ST at inputs must be 1" $
spentST #== 1 spentST #== 1
passert "Signed by all new cosigners" $
pall # plam (\sig -> ptxSignedBy # ctx.txInfo # sig) # newSigs
passert "Signatures are correctly added to cosignature list" $
anyOutput @PProposalDatum # ctx.txInfo
#$ plam
$ \_value address newProposalDatum -> P.do
newProposalF <- pletFields @'["cosigners"] newProposalDatum
let correctDatum =
foldr1
(#&&)
[ newProposalF.cosigners #== proposalF.cosigners
]
foldr1
(#&&)
[ ptraceIfFalse "Datum must be correct" $ correctDatum
, ptraceIfFalse "Must be sent to Proposal's address" $ ownAddress #== pdata address
]
popaque (pconstant ()) popaque (pconstant ())
-------------------------------------------------------------------------- --------------------------------------------------------------------------
PUnlock _r -> P.do PUnlock _r -> P.do

View file

@ -48,8 +48,7 @@ infix 7 .=
forall (sym :: Symbol) (a :: PType) (as :: [PLabeledType]) (s :: S). forall (sym :: Symbol) (a :: PType) (as :: [PLabeledType]) (s :: S).
FieldName sym -> FieldName sym ->
Term s (PAsData a) -> Term s (PAsData a) ->
( RecordMorphism s as ((sym ':= a) ': as) RecordMorphism s as ((sym ':= a) ': as)
)
_ .= x = RecordMorphism $ pcon . PDCons x _ .= x = RecordMorphism $ pcon . PDCons x
infixr 6 .& infixr 6 .&

View file

@ -39,6 +39,7 @@ import Plutarch.Api.V1 (
PPubKeyHash, PPubKeyHash,
PScriptPurpose (PMinting, PSpending), PScriptPurpose (PMinting, PSpending),
PTokenName, PTokenName,
PTxInfo,
PValidator, PValidator,
mintingPolicySymbol, mintingPolicySymbol,
mkMintingPolicy, mkMintingPolicy,
@ -266,13 +267,15 @@ stakePolicy :: Stake -> ClosedTerm PMintingPolicy
stakePolicy stake = stakePolicy stake =
plam $ \_redeemer ctx' -> P.do plam $ \_redeemer ctx' -> P.do
ctx <- pletFields @'["txInfo", "purpose"] ctx' ctx <- pletFields @'["txInfo", "purpose"] ctx'
txInfo' <- plet ctx.txInfo txInfo <- plet $ ctx.txInfo
txInfo <- pletFields @'["mint", "inputs", "outputs"] txInfo' let _a :: Term _ PTxInfo
_a = txInfo
txInfoF <- pletFields @'["mint", "inputs", "outputs"] txInfo
PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose
ownSymbol <- plet $ pfield @"_0" # ownSymbol' ownSymbol <- plet $ pfield @"_0" # ownSymbol'
spentST <- plet $ psymbolValueOf # ownSymbol #$ pvalueSpent # pfromData txInfo' spentST <- plet $ psymbolValueOf # ownSymbol #$ pvalueSpent # txInfoF.inputs
mintedST <- plet $ psymbolValueOf # ownSymbol # txInfo.mint mintedST <- plet $ psymbolValueOf # ownSymbol # txInfoF.mint
let burning = P.do let burning = P.do
passert "ST at inputs must be 1" $ passert "ST at inputs must be 1" $
@ -282,7 +285,7 @@ stakePolicy stake =
mintedST #== -1 mintedST #== -1
passert "An unlocked input existed containing an ST" $ passert "An unlocked input existed containing an ST" $
anyInput @PStakeDatum # pfromData txInfo' anyInput @PStakeDatum # txInfo
#$ plam #$ plam
$ \value _ stakeDatum' -> P.do $ \value _ stakeDatum' -> P.do
let hasST = psymbolValueOf # ownSymbol # value #== 1 let hasST = psymbolValueOf # ownSymbol # value #== 1
@ -299,7 +302,7 @@ stakePolicy stake =
mintedST #== 1 mintedST #== 1
passert "A UTXO must exist with the correct output" $ passert "A UTXO must exist with the correct output" $
anyOutput @PStakeDatum # pfromData txInfo' anyOutput @PStakeDatum # txInfo
#$ plam #$ plam
$ \value address stakeDatum' -> P.do $ \value address stakeDatum' -> P.do
let cred = pfield @"credential" # address let cred = pfield @"credential" # address
@ -359,8 +362,8 @@ stakeValidator :: Stake -> ClosedTerm PValidator
stakeValidator stake = stakeValidator stake =
plam $ \datum redeemer ctx' -> P.do plam $ \datum redeemer ctx' -> P.do
ctx <- pletFields @'["txInfo", "purpose"] ctx' ctx <- pletFields @'["txInfo", "purpose"] ctx'
txInfo' <- plet ctx.txInfo txInfo <- plet $ pfromData ctx.txInfo
txInfo <- pletFields @'["mint", "inputs", "outputs"] txInfo' txInfoF <- pletFields @'["mint", "inputs", "outputs"] txInfo
(pfromData -> stakeRedeemer, _) <- ptryFrom redeemer (pfromData -> stakeRedeemer, _) <- ptryFrom redeemer
@ -371,7 +374,7 @@ stakeValidator stake =
PSpending txOutRef <- pmatch $ pfromData ctx.purpose PSpending txOutRef <- pmatch $ pfromData ctx.purpose
PJust txInInfo <- pmatch $ pfindTxInByTxOutRef # (pfield @"_0" # txOutRef) # txInfo' PJust txInInfo <- pmatch $ pfindTxInByTxOutRef # (pfield @"_0" # txOutRef) # txInfoF.inputs
ownAddress <- plet $ pfield @"address" #$ pfield @"resolved" # txInInfo ownAddress <- plet $ pfield @"address" #$ pfield @"resolved" # txInInfo
let continuingValue = pfield @"value" #$ pfield @"resolved" # txInInfo let continuingValue = pfield @"value" #$ pfield @"resolved" # txInInfo
@ -379,8 +382,8 @@ stakeValidator stake =
ownerSignsTransaction <- plet $ ptxSignedBy # ctx.txInfo # stakeDatum.owner ownerSignsTransaction <- plet $ ptxSignedBy # ctx.txInfo # stakeDatum.owner
stCurrencySymbol <- plet $ pconstant $ mintingPolicySymbol $ mkMintingPolicy (stakePolicy stake) stCurrencySymbol <- plet $ pconstant $ mintingPolicySymbol $ mkMintingPolicy (stakePolicy stake)
mintedST <- plet $ psymbolValueOf # stCurrencySymbol # txInfo.mint mintedST <- plet $ psymbolValueOf # stCurrencySymbol # txInfoF.mint
spentST <- plet $ psymbolValueOf # stCurrencySymbol #$ pvalueSpent # txInfo' spentST <- plet $ psymbolValueOf # stCurrencySymbol #$ pvalueSpent # txInfoF.inputs
-- Is the stake currently locked? -- Is the stake currently locked?
stakeIsLocked <- plet $ stakeLocked # stakeDatum' stakeIsLocked <- plet $ stakeLocked # stakeDatum'
@ -420,7 +423,7 @@ stakeValidator stake =
"Owner signs this transaction" "Owner signs this transaction"
ownerSignsTransaction ownerSignsTransaction
passert "A UTXO must exist with the correct output" $ passert "A UTXO must exist with the correct output" $
anyOutput @PStakeDatum # txInfo' anyOutput @PStakeDatum # txInfo
#$ plam #$ plam
$ \value address newStakeDatum' -> P.do $ \value address newStakeDatum' -> P.do
newStakeDatum <- pletFields @'["owner", "stakedAmount"] newStakeDatum' newStakeDatum <- pletFields @'["owner", "stakedAmount"] newStakeDatum'

View file

@ -249,10 +249,9 @@ paddValue = phoistAcyclic $
) )
-- | Sum of all value at input. -- | Sum of all value at input.
pvalueSpent :: Term s (PTxInfo :--> PValue) pvalueSpent :: Term s (PBuiltinList (PAsData PTxInInfo) :--> PValue)
pvalueSpent = phoistAcyclic $ pvalueSpent = phoistAcyclic $
plam $ \txInfo' -> plam $ \inputs ->
pmatch txInfo' $ \(PTxInfo txInfo) ->
pfoldr pfoldr
# plam # plam
( \txInInfo' v -> ( \txInInfo' v ->
@ -266,13 +265,12 @@ pvalueSpent = phoistAcyclic $
# v # v
) )
# pconstant mempty # pconstant mempty
# (pfield @"inputs" # txInfo) # inputs
-- | Find the TxInInfo by a TxOutRef. -- | Find the TxInInfo by a TxOutRef.
pfindTxInByTxOutRef :: Term s (PTxOutRef :--> PTxInfo :--> PMaybe PTxInInfo) pfindTxInByTxOutRef :: Term s (PTxOutRef :--> PBuiltinList (PAsData PTxInInfo) :--> PMaybe PTxInInfo)
pfindTxInByTxOutRef = phoistAcyclic $ pfindTxInByTxOutRef = phoistAcyclic $
plam $ \txOutRef txInfo' -> plam $ \txOutRef inputs ->
pmatch txInfo' $ \(PTxInfo txInfo) ->
pfindMap pfindMap
# plam # plam
( \txInInfo' -> ( \txInInfo' ->
@ -283,12 +281,29 @@ pfindTxInByTxOutRef = phoistAcyclic $
(pcon (PJust r)) (pcon (PJust r))
(pcon PNothing) (pcon PNothing)
) )
#$ (pfield @"inputs" # txInfo) #$ inputs
-- | True if a list is not empty. -- | True if a list is not empty.
pnotNull :: forall list a. PIsListLike list a => Term _ (list a :--> PBool) pnotNull :: forall list a. PIsListLike list a => Term _ (list a :--> PBool)
pnotNull = phoistAcyclic $ plam $ pelimList (\_ _ -> pcon PTrue) (pcon PFalse) pnotNull = phoistAcyclic $ plam $ pelimList (\_ _ -> pcon PTrue) (pcon PFalse)
-- | 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
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
{- Functions which should (probably) not be upstreamed {- Functions which should (probably) not be upstreamed
All of these functions are quite inefficient. All of these functions are quite inefficient.
@ -372,10 +387,10 @@ psingletonValue = phoistAcyclic $
in res in res
-- | Finds the TxOut of an effect from TxInfo and TxOutRef -- | Finds the TxOut of an effect from TxInfo and TxOutRef
findTxOutByTxOutRef :: Term s (PTxOutRef :--> PTxInfo :--> PMaybe PTxOut) findTxOutByTxOutRef :: Term s (PTxOutRef :--> PBuiltinList (PAsData PTxInInfo) :--> PMaybe PTxOut)
findTxOutByTxOutRef = phoistAcyclic $ findTxOutByTxOutRef = phoistAcyclic $
plam $ \txOutRef txInfo -> plam $ \txOutRef inputs ->
pmatch (pfindTxInByTxOutRef # txOutRef # txInfo) $ \case pmatch (pfindTxInByTxOutRef # txOutRef # inputs) $ \case
PJust ((pfield @"resolved" #) -> txOut) -> pcon $ PJust txOut PJust ((pfield @"resolved" #) -> txOut) -> pcon $ PJust txOut
PNothing -> pcon PNothing PNothing -> pcon PNothing
@ -408,20 +423,3 @@ 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