From 5fc9c30d60bf194c5966516f4090172d8208937d Mon Sep 17 00:00:00 2001 From: fanghr Date: Tue, 12 Apr 2022 18:09:48 +0800 Subject: [PATCH 01/25] add an effect that mutates the governor settings --- agora.cabal | 1 + agora/Agora/Effects/GovernorMutation.hs | 155 ++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 agora/Agora/Effects/GovernorMutation.hs diff --git a/agora.cabal b/agora.cabal index c8ce871..a890add 100644 --- a/agora.cabal +++ b/agora.cabal @@ -131,6 +131,7 @@ library Agora.Effect Agora.Effect.NoOp Agora.Effect.TreasuryWithdrawal + Agora.Effects.GovernorMutation Agora.Governor Agora.Governor.Scripts Agora.MultiSig diff --git a/agora/Agora/Effects/GovernorMutation.hs b/agora/Agora/Effects/GovernorMutation.hs new file mode 100644 index 0000000..5cc03d1 --- /dev/null +++ b/agora/Agora/Effects/GovernorMutation.hs @@ -0,0 +1,155 @@ +{-# LANGUAGE TemplateHaskell #-} + +{- | +Module : Agora.Effects.GovernorMutation +Maintainer : chfanghr@gmail.com +Description: An effect that mutates governor settings + +An effect for mutating governor settings +-} +module Agora.Effects.GovernorMutation (mutateGovernorValidator, PMutateGovernorDatum (..), MutateGovernorDatum (..)) where + +-------------------------------------------------------------------------------- + +import GHC.Generics qualified as GHC +import Generics.SOP (Generic, I (I)) +import Prelude + +-------------------------------------------------------------------------------- + +import Plutarch (popaque) +import Plutarch.Api.V1 ( + PMaybeData (PDJust), + PTxOutRef, + PValidator, + PValue, + ) +import Plutarch.Builtin (pforgetData) +import Plutarch.DataRepr ( + DerivePConstantViaData (..), + PDataFields, + PIsDataReprInstances (PIsDataReprInstances), + ) +import Plutarch.Lift (PLifted, PUnsafeLiftDecl) +import Plutarch.Monadic qualified as P + +-------------------------------------------------------------------------------- + +import Plutus.V1.Ledger.Api (TxOutRef) +import PlutusTx qualified + +-------------------------------------------------------------------------------- + +import Agora.Effect (makeEffect) +import Agora.Governor ( + Governor, + GovernorDatum, + PGovernorDatum, + authorityTokenSymbolFromGovernor, + governorStateTokenAssetClass, + ) +import Agora.Utils ( + containsSingleCurrencySymbol, + findOutputsToAddress, + passert, + passetClassValueOf', + pfindDatum, + ) + +-------------------------------------------------------------------------------- + +data MutateGovernorDatum = MutateGovernorDatum + { governorRef :: TxOutRef + , newDatum :: GovernorDatum + } + deriving stock (Show, GHC.Generic) + deriving anyclass (Generic) + +PlutusTx.makeIsDataIndexed ''MutateGovernorDatum [('MutateGovernorDatum, 0)] + +-------------------------------------------------------------------------------- + +newtype PMutateGovernorDatum (s :: S) + = PMutateGovernorDatum + ( Term + s + ( PDataRecord + '[ "governorRef" ':= PTxOutRef + , "newDatum" ':= PGovernorDatum + ] + ) + ) + deriving stock (GHC.Generic) + deriving anyclass (Generic) + deriving anyclass (PIsDataRepr) + deriving + (PlutusType, PIsData, PDataFields) + via (PIsDataReprInstances PMutateGovernorDatum) + +instance PUnsafeLiftDecl PMutateGovernorDatum where type PLifted PMutateGovernorDatum = MutateGovernorDatum +deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) instance (PConstant MutateGovernorDatum) + +-------------------------------------------------------------------------------- + +mutateGovernorValidator :: Governor -> ClosedTerm PValidator +mutateGovernorValidator gov = makeEffect gatSymbol $ + \_gatCs (datum :: Term _ PMutateGovernorDatum) _txOutRef txInfo' -> P.do + let newDatum = pforgetData $ pfield @"newDatum" # datum + pinnedGovernor = pfield @"governorRef" # datum + + txInfo <- pletFields @'["mint", "inputs", "outputs"] txInfo' + + passert "Nothing should be minted/burnt other than GAT" $ + containsSingleCurrencySymbol # txInfo.mint + + filteredInputs <- + plet $ + pfilter + # ( plam $ \inInfo -> + let value = pfield @"value" #$ pfield @"resolved" # inInfo + in gstValueOf # value #== 1 + ) + # pfromData txInfo.inputs + + passert "Governor's state token must be moved" $ + plength # filteredInputs #== 1 + + input <- plet $ phead # filteredInputs + + passert "Can only modify the pinned governor" $ + pfield @"outRef" # input #== pinnedGovernor + + let govAddress = + pfield @"address" + #$ pfield @"resolved" + #$ pfromData input + + filteredOutputs <- plet $ findOutputsToAddress # pfromData txInfo' # govAddress + + passert "Exactly one output to the governor" $ + plength # filteredOutputs #== 1 + + outputToGovernor <- plet $ phead # filteredOutputs + + passert "Governor's state token must stay at governor's address" $ + (gstValueOf #$ pfield @"value" # outputToGovernor) #== 1 + + outputDatumHash' <- pmatch $ pfromData $ pfield @"datumHash" # outputToGovernor + + case outputDatumHash' of + PDJust ((pfromData . (pfield @"_0" #)) -> outputDatumHash) -> P.do + datum' <- pmatch $ pfindDatum # outputDatumHash # pfromData txInfo' + case datum' of + PJust datum -> P.do + passert "Unexpected output datum" $ + pto datum #== newDatum + + popaque $ pconstant () + _ -> ptraceError "Output datum not found" + _ -> ptraceError "Ouput to governor should have datum" + where + gatSymbol = authorityTokenSymbolFromGovernor gov + gstAssetClass = governorStateTokenAssetClass gov + + gstValueOf :: Term s (PValue :--> PInteger) + gstValueOf = passetClassValueOf' gstAssetClass From 94d6d465af5893b17ea10ce3c8a3b18c298de81d Mon Sep 17 00:00:00 2001 From: fanghr Date: Fri, 22 Apr 2022 18:19:01 +0800 Subject: [PATCH 02/25] fix compilation errors --- agora/Agora/Effects/GovernorMutation.hs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/agora/Agora/Effects/GovernorMutation.hs b/agora/Agora/Effects/GovernorMutation.hs index 5cc03d1..c6c5f87 100644 --- a/agora/Agora/Effects/GovernorMutation.hs +++ b/agora/Agora/Effects/GovernorMutation.hs @@ -23,6 +23,8 @@ import Plutarch.Api.V1 ( PTxOutRef, PValidator, PValue, + mintingPolicySymbol, + mkMintingPolicy, ) import Plutarch.Builtin (pforgetData) import Plutarch.DataRepr ( @@ -40,16 +42,15 @@ import PlutusTx qualified -------------------------------------------------------------------------------- +import Agora.AuthorityToken import Agora.Effect (makeEffect) import Agora.Governor ( Governor, GovernorDatum, PGovernorDatum, - authorityTokenSymbolFromGovernor, - governorStateTokenAssetClass, + gstAssetClass, ) import Agora.Utils ( - containsSingleCurrencySymbol, findOutputsToAddress, passert, passetClassValueOf', @@ -99,8 +100,11 @@ mutateGovernorValidator gov = makeEffect gatSymbol $ txInfo <- pletFields @'["mint", "inputs", "outputs"] txInfo' + let mint :: Term _ (PBuiltinList _) + mint = pto $ pto $ pto $ pfromData txInfo.mint + passert "Nothing should be minted/burnt other than GAT" $ - containsSingleCurrencySymbol # txInfo.mint + plength # mint #== 1 filteredInputs <- plet $ @@ -148,8 +152,12 @@ mutateGovernorValidator gov = makeEffect gatSymbol $ _ -> ptraceError "Output datum not found" _ -> ptraceError "Ouput to governor should have datum" where - gatSymbol = authorityTokenSymbolFromGovernor gov - gstAssetClass = governorStateTokenAssetClass gov + -- Copy-Paste from governor + -- TODO: export as a util function from governor + gatSymbol = mintingPolicySymbol policy + where + at = AuthorityToken $ gstAssetClass gov + policy = mkMintingPolicy $ authorityTokenPolicy at gstValueOf :: Term s (PValue :--> PInteger) - gstValueOf = passetClassValueOf' gstAssetClass + gstValueOf = passetClassValueOf' $ gstAssetClass gov From 4731614ac91fce3cc4f30f56401be6bd75d24999 Mon Sep 17 00:00:00 2001 From: fanghr Date: Fri, 22 Apr 2022 18:49:43 +0800 Subject: [PATCH 03/25] utilize `gatSymbol`; clean up imports --- agora/Agora/Effects/GovernorMutation.hs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/agora/Agora/Effects/GovernorMutation.hs b/agora/Agora/Effects/GovernorMutation.hs index c6c5f87..baae4d3 100644 --- a/agora/Agora/Effects/GovernorMutation.hs +++ b/agora/Agora/Effects/GovernorMutation.hs @@ -23,8 +23,6 @@ import Plutarch.Api.V1 ( PTxOutRef, PValidator, PValue, - mintingPolicySymbol, - mkMintingPolicy, ) import Plutarch.Builtin (pforgetData) import Plutarch.DataRepr ( @@ -42,13 +40,13 @@ import PlutusTx qualified -------------------------------------------------------------------------------- -import Agora.AuthorityToken import Agora.Effect (makeEffect) import Agora.Governor ( Governor, GovernorDatum, PGovernorDatum, gstAssetClass, + gatSymbol, ) import Agora.Utils ( findOutputsToAddress, @@ -93,7 +91,7 @@ deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) i -------------------------------------------------------------------------------- mutateGovernorValidator :: Governor -> ClosedTerm PValidator -mutateGovernorValidator gov = makeEffect gatSymbol $ +mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ \_gatCs (datum :: Term _ PMutateGovernorDatum) _txOutRef txInfo' -> P.do let newDatum = pforgetData $ pfield @"newDatum" # datum pinnedGovernor = pfield @"governorRef" # datum @@ -152,12 +150,5 @@ mutateGovernorValidator gov = makeEffect gatSymbol $ _ -> ptraceError "Output datum not found" _ -> ptraceError "Ouput to governor should have datum" where - -- Copy-Paste from governor - -- TODO: export as a util function from governor - gatSymbol = mintingPolicySymbol policy - where - at = AuthorityToken $ gstAssetClass gov - policy = mkMintingPolicy $ authorityTokenPolicy at - gstValueOf :: Term s (PValue :--> PInteger) gstValueOf = passetClassValueOf' $ gstAssetClass gov From eb6b617d4d1d93baaaa24cff6a260f88d3e48e81 Mon Sep 17 00:00:00 2001 From: fanghr Date: Mon, 25 Apr 2022 17:29:25 +0800 Subject: [PATCH 04/25] add document for everything in `GovernorMutation.hs` --- agora/Agora/Effects/GovernorMutation.hs | 34 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/agora/Agora/Effects/GovernorMutation.hs b/agora/Agora/Effects/GovernorMutation.hs index baae4d3..e83225a 100644 --- a/agora/Agora/Effects/GovernorMutation.hs +++ b/agora/Agora/Effects/GovernorMutation.hs @@ -7,7 +7,16 @@ Description: An effect that mutates governor settings An effect for mutating governor settings -} -module Agora.Effects.GovernorMutation (mutateGovernorValidator, PMutateGovernorDatum (..), MutateGovernorDatum (..)) where +module Agora.Effects.GovernorMutation ( + -- * Haskell-land + MutateGovernorDatum (..), + + -- * Plutarch-land + PMutateGovernorDatum (..), + + -- * Scripts + mutateGovernorValidator, +) where -------------------------------------------------------------------------------- @@ -45,8 +54,8 @@ import Agora.Governor ( Governor, GovernorDatum, PGovernorDatum, - gstAssetClass, gatSymbol, + gstAssetClass, ) import Agora.Utils ( findOutputsToAddress, @@ -57,9 +66,12 @@ import Agora.Utils ( -------------------------------------------------------------------------------- +-- | Haskell-level datum for the governor mutation effect script. data MutateGovernorDatum = MutateGovernorDatum - { governorRef :: TxOutRef + { governorRef :: TxOutRef + -- ^ Referenced governor state UTXO should be updated by the effect. , newDatum :: GovernorDatum + -- ^ The new settings for the governor. } deriving stock (Show, GHC.Generic) deriving anyclass (Generic) @@ -68,6 +80,7 @@ PlutusTx.makeIsDataIndexed ''MutateGovernorDatum [('MutateGovernorDatum, 0)] -------------------------------------------------------------------------------- +-- | Plutarch-level version of 'MutateGovernorDatum'. newtype PMutateGovernorDatum (s :: S) = PMutateGovernorDatum ( Term @@ -90,6 +103,21 @@ deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) i -------------------------------------------------------------------------------- +{- | Validator for the governor mutation effect. + + This effect is implemented using the 'Agora.Effect.makeEffect' wrapper, + meaning that the burning of GAT is checked in the said wrapper. + + In order to locate the governor, the validator is parametrized with a 'Agora.Governor.Governor'. + + All the information it need to validate the effect is encoded in the 'MutateGovernorDatum', + so regardless what redeemer it's given, it will check: + + - No token is minted/burnt other than GAT. + - The reference UTXO in the datum should be spent. + - Said UTXO carries the GST. + - A new UTXO, containing the GST and the new governor state datum, is paid to the governor. +-} mutateGovernorValidator :: Governor -> ClosedTerm PValidator mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ \_gatCs (datum :: Term _ PMutateGovernorDatum) _txOutRef txInfo' -> P.do From 7c5c8d423af8a0fda3a288e9c5e033cd67e006a4 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 13:29:36 +0800 Subject: [PATCH 05/25] move `GovernorMutation` effect to `Effect` --- agora.cabal | 2 +- .../{Effects => Effect}/GovernorMutation.hs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) rename agora/Agora/{Effects => Effect}/GovernorMutation.hs (94%) diff --git a/agora.cabal b/agora.cabal index a890add..b3005cc 100644 --- a/agora.cabal +++ b/agora.cabal @@ -129,9 +129,9 @@ library exposed-modules: Agora.AuthorityToken Agora.Effect + Agora.Effect.GovernorMutation Agora.Effect.NoOp Agora.Effect.TreasuryWithdrawal - Agora.Effects.GovernorMutation Agora.Governor Agora.Governor.Scripts Agora.MultiSig diff --git a/agora/Agora/Effects/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs similarity index 94% rename from agora/Agora/Effects/GovernorMutation.hs rename to agora/Agora/Effect/GovernorMutation.hs index e83225a..783b9f8 100644 --- a/agora/Agora/Effects/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -1,19 +1,19 @@ {-# LANGUAGE TemplateHaskell #-} {- | -Module : Agora.Effects.GovernorMutation +Module : Agora.Effect.GovernorMutation Maintainer : chfanghr@gmail.com Description: An effect that mutates governor settings An effect for mutating governor settings -} -module Agora.Effects.GovernorMutation ( +module Agora.Effect.GovernorMutation ( -- * Haskell-land MutateGovernorDatum (..), -- * Plutarch-land PMutateGovernorDatum (..), - + -- * Scripts mutateGovernorValidator, ) where @@ -68,10 +68,10 @@ import Agora.Utils ( -- | Haskell-level datum for the governor mutation effect script. data MutateGovernorDatum = MutateGovernorDatum - { governorRef :: TxOutRef - -- ^ Referenced governor state UTXO should be updated by the effect. + { governorRef :: TxOutRef + -- ^ Referenced governor state UTXO should be updated by the effect. , newDatum :: GovernorDatum - -- ^ The new settings for the governor. + -- ^ The new settings for the governor. } deriving stock (Show, GHC.Generic) deriving anyclass (Generic) @@ -103,9 +103,9 @@ deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) i -------------------------------------------------------------------------------- -{- | Validator for the governor mutation effect. +{- | Validator for the governor mutation effect. - This effect is implemented using the 'Agora.Effect.makeEffect' wrapper, + This effect is implemented using the 'Agora.Effect.makeEffect' wrapper, meaning that the burning of GAT is checked in the said wrapper. In order to locate the governor, the validator is parametrized with a 'Agora.Governor.Governor'. From b5dd2f6932aa774deb798db07b6087496a9b6154 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 13:34:09 +0800 Subject: [PATCH 06/25] mlabs email --- agora/Agora/Effect/GovernorMutation.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 783b9f8..8d40524 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -2,7 +2,7 @@ {- | Module : Agora.Effect.GovernorMutation -Maintainer : chfanghr@gmail.com +Maintainer : connor@mlabs.city Description: An effect that mutates governor settings An effect for mutating governor settings From 19f5481ef2800088e85086016c2cd03d7edf7509 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 14:08:11 +0800 Subject: [PATCH 07/25] fix compilation errors --- agora/Agora/Effect/GovernorMutation.hs | 41 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 8d40524..af98850 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -20,31 +20,34 @@ module Agora.Effect.GovernorMutation ( -------------------------------------------------------------------------------- +import Control.Applicative (Const) import GHC.Generics qualified as GHC import Generics.SOP (Generic, I (I)) -import Prelude -------------------------------------------------------------------------------- -import Plutarch (popaque) import Plutarch.Api.V1 ( PMaybeData (PDJust), PTxOutRef, PValidator, PValue, ) +import Plutarch.Api.V1.Extra (pvalueOf) import Plutarch.Builtin (pforgetData) import Plutarch.DataRepr ( DerivePConstantViaData (..), PDataFields, PIsDataReprInstances (PIsDataReprInstances), ) -import Plutarch.Lift (PLifted, PUnsafeLiftDecl) +import Plutarch.Lift (PConstantDecl, PLifted, PUnsafeLiftDecl) import Plutarch.Monadic qualified as P +import Plutarch.TryFrom (PTryFrom (..)) +import Plutarch.Unsafe (punsafeCoerce) -------------------------------------------------------------------------------- import Plutus.V1.Ledger.Api (TxOutRef) +import Plutus.V1.Ledger.Value (AssetClass (..)) import PlutusTx qualified -------------------------------------------------------------------------------- @@ -54,13 +57,14 @@ import Agora.Governor ( Governor, GovernorDatum, PGovernorDatum, - gatSymbol, - gstAssetClass, + ) +import Agora.Governor.Scripts ( + authorityTokenSymbolFromGovernor, + governorSTAssetClassFromGovernor, ) import Agora.Utils ( findOutputsToAddress, passert, - passetClassValueOf', pfindDatum, ) @@ -99,7 +103,13 @@ newtype PMutateGovernorDatum (s :: S) via (PIsDataReprInstances PMutateGovernorDatum) instance PUnsafeLiftDecl PMutateGovernorDatum where type PLifted PMutateGovernorDatum = MutateGovernorDatum -deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) instance (PConstant MutateGovernorDatum) +deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) instance (PConstantDecl MutateGovernorDatum) + +-- TODO: Derive this. +instance PTryFrom PData PMutateGovernorDatum where + type PTryFromExcess PData PMutateGovernorDatum = Const () + ptryFrom' d k = + k (punsafeCoerce d, ()) -------------------------------------------------------------------------------- @@ -119,12 +129,12 @@ deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) i - A new UTXO, containing the GST and the new governor state datum, is paid to the governor. -} mutateGovernorValidator :: Governor -> ClosedTerm PValidator -mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ +mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) $ \_gatCs (datum :: Term _ PMutateGovernorDatum) _txOutRef txInfo' -> P.do let newDatum = pforgetData $ pfield @"newDatum" # datum pinnedGovernor = pfield @"governorRef" # datum - txInfo <- pletFields @'["mint", "inputs", "outputs"] txInfo' + txInfo <- pletFields @'["mint", "inputs", "outputs", "datums"] txInfo' let mint :: Term _ (PBuiltinList _) mint = pto $ pto $ pto $ pfromData txInfo.mint @@ -135,7 +145,8 @@ mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ filteredInputs <- plet $ pfilter - # ( plam $ \inInfo -> + # plam + ( \inInfo -> let value = pfield @"value" #$ pfield @"resolved" # inInfo in gstValueOf # value #== 1 ) @@ -154,7 +165,7 @@ mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ #$ pfield @"resolved" #$ pfromData input - filteredOutputs <- plet $ findOutputsToAddress # pfromData txInfo' # govAddress + filteredOutputs <- plet $ findOutputsToAddress # pfromData txInfo.outputs # govAddress passert "Exactly one output to the governor" $ plength # filteredOutputs #== 1 @@ -167,8 +178,8 @@ mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ outputDatumHash' <- pmatch $ pfromData $ pfield @"datumHash" # outputToGovernor case outputDatumHash' of - PDJust ((pfromData . (pfield @"_0" #)) -> outputDatumHash) -> P.do - datum' <- pmatch $ pfindDatum # outputDatumHash # pfromData txInfo' + PDJust (pfromData . (pfield @"_0" #) -> outputDatumHash) -> P.do + datum' <- pmatch $ pfindDatum # outputDatumHash # pfromData txInfo.datums case datum' of PJust datum -> P.do passert "Unexpected output datum" $ @@ -179,4 +190,6 @@ mutateGovernorValidator gov = makeEffect (gatSymbol gov) $ _ -> ptraceError "Ouput to governor should have datum" where gstValueOf :: Term s (PValue :--> PInteger) - gstValueOf = passetClassValueOf' $ gstAssetClass gov + gstValueOf = phoistAcyclic $ plam $ \v -> pvalueOf # v # pconstant cs # pconstant tn + where + AssetClass (cs, tn) = governorSTAssetClassFromGovernor gov From 9dc4a87ab39b85a50ea26e997880def1b9625c2e Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 14:13:33 +0800 Subject: [PATCH 08/25] require `PtryFrom PData (PAsData datum)` in `makeEffect` --- agora/Agora/Effect.hs | 4 ++-- agora/Agora/Effect/GovernorMutation.hs | 4 ++-- agora/Agora/Effect/NoOp.hs | 6 +++--- agora/Agora/Effect/TreasuryWithdrawal.hs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/agora/Agora/Effect.hs b/agora/Agora/Effect.hs index 8fb40ba..c35ed55 100644 --- a/agora/Agora/Effect.hs +++ b/agora/Agora/Effect.hs @@ -23,7 +23,7 @@ import Plutus.V1.Ledger.Value (CurrencySymbol) -} makeEffect :: forall (datum :: PType). - (PIsData datum, PTryFrom PData datum) => + (PIsData datum, PTryFrom PData (PAsData datum)) => CurrencySymbol -> (forall (s :: S). Term s PCurrencySymbol -> Term s datum -> Term s PTxOutRef -> Term s (PAsData PTxInfo) -> Term s POpaque) -> ClosedTerm PValidator @@ -35,7 +35,7 @@ makeEffect gatCs' f = -- convert input datum, PData, into desierable type -- the way this conversion is performed should be defined -- by PTryFrom for each datum in effect script. - (datum', _) <- tctryFrom @datum datum + (pfromData -> datum', _) <- tctryFrom datum -- ensure purpose is Spending. PSpending txOutRef <- tcmatch $ pfromData ctx.purpose diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index af98850..20ec5ba 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -106,8 +106,8 @@ instance PUnsafeLiftDecl PMutateGovernorDatum where type PLifted PMutateGovernor deriving via (DerivePConstantViaData MutateGovernorDatum PMutateGovernorDatum) instance (PConstantDecl MutateGovernorDatum) -- TODO: Derive this. -instance PTryFrom PData PMutateGovernorDatum where - type PTryFromExcess PData PMutateGovernorDatum = Const () +instance PTryFrom PData (PAsData PMutateGovernorDatum) where + type PTryFromExcess PData (PAsData PMutateGovernorDatum) = Const () ptryFrom' d k = k (punsafeCoerce d, ()) diff --git a/agora/Agora/Effect/NoOp.hs b/agora/Agora/Effect/NoOp.hs index a384675..39c63ee 100644 --- a/agora/Agora/Effect/NoOp.hs +++ b/agora/Agora/Effect/NoOp.hs @@ -18,13 +18,13 @@ import Plutus.V1.Ledger.Value (CurrencySymbol) newtype PNoOp (s :: S) = PNoOp (Term s PUnit) deriving (PlutusType, PIsData) via (DerivePNewtype PNoOp PUnit) -instance PTryFrom PData PNoOp where - type PTryFromExcess PData PNoOp = Const () +instance PTryFrom PData (PAsData PNoOp) where + type PTryFromExcess PData (PAsData PNoOp) = Const () ptryFrom' _ cont = -- JUSTIFICATION: -- We don't care anything about data. -- It should always be reduced to Unit. - cont (pcon $ PNoOp (pconstant ()), ()) + cont (pdata $ pcon $ PNoOp (pconstant ()), ()) -- | Dummy effect which can only burn its GAT. noOpValidator :: CurrencySymbol -> ClosedTerm PValidator diff --git a/agora/Agora/Effect/TreasuryWithdrawal.hs b/agora/Agora/Effect/TreasuryWithdrawal.hs index 5bad045..6bb2851 100644 --- a/agora/Agora/Effect/TreasuryWithdrawal.hs +++ b/agora/Agora/Effect/TreasuryWithdrawal.hs @@ -82,8 +82,8 @@ deriving via instance (PConstantDecl TreasuryWithdrawalDatum) -instance PTryFrom PData PTreasuryWithdrawalDatum where - type PTryFromExcess PData PTreasuryWithdrawalDatum = Const () +instance PTryFrom PData (PAsData PTreasuryWithdrawalDatum) where + type PTryFromExcess PData (PAsData PTreasuryWithdrawalDatum) = Const () ptryFrom' opq cont = -- TODO: This should not use 'punsafeCoerce'. -- Blocked by 'PCredential', and 'PTuple'. From ccf8229eed293d6d6a4b17f6a55d1d8085b7cd30 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 17:00:59 +0800 Subject: [PATCH 09/25] small doc fix to `pisJust` --- agora/Agora/Utils.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 558bc13..f37712b 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -212,7 +212,7 @@ pfromMaybe = phoistAcyclic $ PJust a' -> a' PNothing -> e --- | Yield True if a given PMaybe is of form PJust _. +-- | Yield True if a given PMaybe is of form @'PJust' _@. pisJust :: forall a s. Term s (PMaybe a :--> PBool) pisJust = phoistAcyclic $ plam $ \v' -> From 1b4f51b500a7f979c0af5730883f8f6f8eb1574a Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 17:03:47 +0800 Subject: [PATCH 10/25] safely check input/output governor datum ...utilize a bunch of util functions as well --- agora/Agora/Effect/GovernorMutation.hs | 55 +++++++++++++++----------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 20ec5ba..af7cee1 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -27,13 +27,11 @@ import Generics.SOP (Generic, I (I)) -------------------------------------------------------------------------------- import Plutarch.Api.V1 ( - PMaybeData (PDJust), PTxOutRef, PValidator, PValue, ) import Plutarch.Api.V1.Extra (pvalueOf) -import Plutarch.Builtin (pforgetData) import Plutarch.DataRepr ( DerivePConstantViaData (..), PDataFields, @@ -57,6 +55,7 @@ import Agora.Governor ( Governor, GovernorDatum, PGovernorDatum, + governorDatumValid, ) import Agora.Governor.Scripts ( authorityTokenSymbolFromGovernor, @@ -64,8 +63,11 @@ import Agora.Governor.Scripts ( ) import Agora.Utils ( findOutputsToAddress, + findTxOutByTxOutRef, + mustBePDJust, + mustBePJust, passert, - pfindDatum, + ptryFindDatum, ) -------------------------------------------------------------------------------- @@ -99,7 +101,7 @@ newtype PMutateGovernorDatum (s :: S) deriving anyclass (Generic) deriving anyclass (PIsDataRepr) deriving - (PlutusType, PIsData, PDataFields) + (PlutusType, PIsData, PDataFields, PEq) via (PIsDataReprInstances PMutateGovernorDatum) instance PUnsafeLiftDecl PMutateGovernorDatum where type PLifted PMutateGovernorDatum = MutateGovernorDatum @@ -130,12 +132,19 @@ instance PTryFrom PData (PAsData PMutateGovernorDatum) where -} mutateGovernorValidator :: Governor -> ClosedTerm PValidator mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) $ - \_gatCs (datum :: Term _ PMutateGovernorDatum) _txOutRef txInfo' -> P.do - let newDatum = pforgetData $ pfield @"newDatum" # datum - pinnedGovernor = pfield @"governorRef" # datum + \_gatCs (datum' :: Term _ PMutateGovernorDatum) txOutRef txInfo' -> P.do + datum <- pletFields @'["newDatum", "governorRef"] datum' txInfo <- pletFields @'["mint", "inputs", "outputs", "datums"] txInfo' + let selfAddress = + pfield @"address" + #$ mustBePJust # "Self governorInput not found" + #$ findTxOutByTxOutRef # txOutRef # txInfo.inputs + + passert "No output to the effect validator" $ + pnull #$ findOutputsToAddress # txInfo.outputs # selfAddress + let mint :: Term _ (PBuiltinList _) mint = pto $ pto $ pto $ pfromData txInfo.mint @@ -155,39 +164,39 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) passert "Governor's state token must be moved" $ plength # filteredInputs #== 1 - input <- plet $ phead # filteredInputs + governorInput <- plet $ phead # filteredInputs passert "Can only modify the pinned governor" $ - pfield @"outRef" # input #== pinnedGovernor + pfield @"outRef" # governorInput #== datum.governorRef let govAddress = pfield @"address" #$ pfield @"resolved" - #$ pfromData input + #$ pfromData governorInput filteredOutputs <- plet $ findOutputsToAddress # pfromData txInfo.outputs # govAddress passert "Exactly one output to the governor" $ plength # filteredOutputs #== 1 - outputToGovernor <- plet $ phead # filteredOutputs + governorOutput <- plet $ phead # filteredOutputs passert "Governor's state token must stay at governor's address" $ - (gstValueOf #$ pfield @"value" # outputToGovernor) #== 1 + (gstValueOf #$ pfield @"value" # governorOutput) #== 1 - outputDatumHash' <- pmatch $ pfromData $ pfield @"datumHash" # outputToGovernor + let governorOutputDatumHash = + mustBePDJust # "Governor output doesn't have datum" + #$ pfromData + $ pfield @"datumHash" # governorOutput + governorOutputDatum = + pfromData @PGovernorDatum $ + mustBePJust # "Governor output datum not found" + #$ ptryFindDatum # governorOutputDatumHash # txInfo.datums - case outputDatumHash' of - PDJust (pfromData . (pfield @"_0" #) -> outputDatumHash) -> P.do - datum' <- pmatch $ pfindDatum # outputDatumHash # pfromData txInfo.datums - case datum' of - PJust datum -> P.do - passert "Unexpected output datum" $ - pto datum #== newDatum + passert "Unexpected governor datum" $ datum.newDatum #== governorOutputDatum + passert "New governor datum should be valid" $ governorDatumValid # governorOutputDatum - popaque $ pconstant () - _ -> ptraceError "Output datum not found" - _ -> ptraceError "Ouput to governor should have datum" + popaque $ pconstant () where gstValueOf :: Term s (PValue :--> PInteger) gstValueOf = phoistAcyclic $ plam $ \v -> pvalueOf # v # pconstant cs # pconstant tn From 5eebec544e462f262ebbb9c8da84c352258629bd Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 17:26:49 +0800 Subject: [PATCH 11/25] improve the docstring --- agora/Agora/Effect/GovernorMutation.hs | 30 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index af7cee1..628f130 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -3,9 +3,9 @@ {- | Module : Agora.Effect.GovernorMutation Maintainer : connor@mlabs.city -Description: An effect that mutates governor settings +Description: An effect that mutates governor settings. -An effect for mutating governor settings +An effect for mutating governor settings. -} module Agora.Effect.GovernorMutation ( -- * Haskell-land @@ -117,18 +117,26 @@ instance PTryFrom PData (PAsData PMutateGovernorDatum) where {- | Validator for the governor mutation effect. - This effect is implemented using the 'Agora.Effect.makeEffect' wrapper, - meaning that the burning of GAT is checked in the said wrapper. + This effect is implemented using the 'Agora.Effect.makeEffect' wrapper, + meaning that the burning of GAT is checked in the said wrapper. - In order to locate the governor, the validator is parametrized with a 'Agora.Governor.Governor'. + In order to locate the governor, the validator is parametrized with a 'Agora.Governor.Governor'. - All the information it need to validate the effect is encoded in the 'MutateGovernorDatum', - so regardless what redeemer it's given, it will check: + All the information it needs to validate the effect is encoded in the 'MutateGovernorDatum', + so regardless what redeemer it's given, it will check: - - No token is minted/burnt other than GAT. - - The reference UTXO in the datum should be spent. - - Said UTXO carries the GST. - - A new UTXO, containing the GST and the new governor state datum, is paid to the governor. + - No token is minted/burnt other than GAT. + - Nothing is being paid to the the effect validator. + - The governor's state UTXO must be spent: + + * It carries exactly one GST. + * It's referenced by 'governorRef' in the effect's datum. + + - A new state UTXO is paid to the governor: + + * It contains the GST. + * It has valid governor state datum. + * The datum is exactly the same as the 'newDatum'. -} mutateGovernorValidator :: Governor -> ClosedTerm PValidator mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) $ From 30cceb7910f389fbb37557382d2f5e212ec4b7e2 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 17:36:33 +0800 Subject: [PATCH 12/25] add templates of tests and samples --- agora-sample/Sample/Effect/GovernorMutation.hs | 1 + agora-test/Spec.hs | 4 ++++ agora-test/Spec/Effect/GovernorMutation.hs | 6 ++++++ agora.cabal | 2 ++ 4 files changed, 13 insertions(+) create mode 100644 agora-sample/Sample/Effect/GovernorMutation.hs create mode 100644 agora-test/Spec/Effect/GovernorMutation.hs diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs new file mode 100644 index 0000000..d369707 --- /dev/null +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -0,0 +1 @@ +module Sample.Effect.GovernorMutation () where diff --git a/agora-test/Spec.hs b/agora-test/Spec.hs index d2c90f7..2d97c1e 100644 --- a/agora-test/Spec.hs +++ b/agora-test/Spec.hs @@ -7,6 +7,7 @@ import Test.Tasty (defaultMain, testGroup) -------------------------------------------------------------------------------- import Spec.AuthorityToken qualified as AuthorityToken +import Spec.Effect.GovernorMutation qualified as GovernorMutation import Spec.Effect.TreasuryWithdrawal qualified as TreasuryWithdrawal import Spec.Governor qualified as Governor import Spec.Model.MultiSig qualified as MultiSig @@ -26,6 +27,9 @@ main = [ testGroup "Treasury Withdrawal Effect" TreasuryWithdrawal.tests + , testGroup + "Governor Mutation Effect" + GovernorMutation.tests ] , testGroup "Stake tests" diff --git a/agora-test/Spec/Effect/GovernorMutation.hs b/agora-test/Spec/Effect/GovernorMutation.hs new file mode 100644 index 0000000..7863cb6 --- /dev/null +++ b/agora-test/Spec/Effect/GovernorMutation.hs @@ -0,0 +1,6 @@ +module Spec.Effect.GovernorMutation (tests) where + +import Test.Tasty (TestTree) + +tests :: [TestTree] +tests = [] diff --git a/agora.cabal b/agora.cabal index b3005cc..88f32f0 100644 --- a/agora.cabal +++ b/agora.cabal @@ -167,6 +167,7 @@ library agora-sample import: lang, deps, test-deps build-depends: agora-testlib exposed-modules: + Sample.Effect.GovernorMutation Sample.Effect.TreasuryWithdrawal Sample.Governor Sample.Proposal @@ -183,6 +184,7 @@ test-suite agora-test hs-source-dirs: agora-test other-modules: Spec.AuthorityToken + Spec.Effect.GovernorMutation Spec.Effect.TreasuryWithdrawal Spec.Governor Spec.Model.MultiSig From 023fcc8e6f9321d5de7abd08b8f3420492009374 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 18:25:53 +0800 Subject: [PATCH 13/25] add a valid sample for the mutate governor effect --- .../Sample/Effect/GovernorMutation.hs | 142 +++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs index d369707..be6e167 100644 --- a/agora-sample/Sample/Effect/GovernorMutation.hs +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -1 +1,141 @@ -module Sample.Effect.GovernorMutation () where +module Sample.Effect.GovernorMutation ( + validContext, + effectValidator, + effectValidatorAddress, + effectValidatorHash, + atAssetClass, +) where + +import Agora.Effect.GovernorMutation ( + MutateGovernorDatum (..), + mutateGovernorValidator, + ) +import Agora.Governor (GovernorDatum (..)) +import Agora.Proposal (ProposalId (..)) +import Plutarch.Api.V1 (mkValidator, validatorHash) +import Plutus.V1.Ledger.Address (scriptHashAddress) +import Plutus.V1.Ledger.Api ( + Address, + Datum (..), + ScriptContext (..), + ScriptPurpose (Spending), + ToData (..), + TokenName (..), + TxInInfo (..), + TxInfo (..), + TxOut (..), + TxOutRef (TxOutRef), + Validator, + ValidatorHash (..), + ) +import Plutus.V1.Ledger.Api qualified as Interval +import Plutus.V1.Ledger.Value (AssetClass, assetClass) +import Plutus.V1.Ledger.Value qualified as Value +import Sample.Shared +import Test.Util (datumPair, toDatumHash) + +effectValidator :: Validator +effectValidator = mkValidator $ mutateGovernorValidator governor + +effectValidatorHash :: ValidatorHash +effectValidatorHash = validatorHash effectValidator + +effectValidatorAddress :: Address +effectValidatorAddress = scriptHashAddress effectValidatorHash + +atAssetClass :: AssetClass +atAssetClass = assetClass authorityTokenSymbol tokenName + where + -- TODO: use 'validatorHashToTokenName' + ValidatorHash bs = effectValidatorHash + tokenName = TokenName bs + +validContext :: ScriptContext +validContext = + let gst = Value.assetClassValue govAssetClass 1 + at = Value.assetClassValue atAssetClass 1 + + burnt = Value.assetClassValue atAssetClass (-1) + + -- + + governorInputRef :: TxOutRef + governorInputRef = TxOutRef "614481d2159bfb72350222d61fce17e548e0fc00e5a1f841ff1837c431346ce7" 1 + + -- + + governorInputDatum' :: GovernorDatum + governorInputDatum' = + GovernorDatum + { proposalThresholds = defaultProposalThresholds + , nextProposalId = ProposalId 0 + } + governorInputDatum :: Datum + governorInputDatum = Datum $ toBuiltinData governorInputDatum' + governorInput :: TxOut + governorInput = + TxOut + { txOutAddress = govValidatorAddress + , txOutValue = gst + , txOutDatumHash = Just $ toDatumHash governorInputDatum + } + + -- + + -- The effect should update 'nextProposalId' + effectInputDatum' :: MutateGovernorDatum + effectInputDatum' = + MutateGovernorDatum + { governorRef = governorInputRef + , newDatum = + governorInputDatum' + { nextProposalId = ProposalId 42 + } + } + effectInputDatum :: Datum + effectInputDatum = Datum $ toBuiltinData effectInputDatum' + effectInput :: TxOut + effectInput = + TxOut + { txOutAddress = effectValidatorAddress + , txOutValue = at + , txOutDatumHash = Just $ toDatumHash effectInputDatum + } + + -- + + governorOutputDatum' :: GovernorDatum + governorOutputDatum' = effectInputDatum'.newDatum + governorOutputDatum :: Datum + governorOutputDatum = Datum $ toBuiltinData governorOutputDatum' + governorOutput :: TxOut + governorOutput = + TxOut + { txOutAddress = effectValidatorAddress + , txOutValue = withMinAda gst + , txOutDatumHash = Just $ toDatumHash governorOutputDatum + } + + -- + + ownInputRef :: TxOutRef + ownInputRef = TxOutRef "c31164dc11835de7eb6187f67d0e1a19c1dfc0786a456923eef5043189cdb578" 1 + in ScriptContext + { scriptContextPurpose = Spending ownInputRef + , scriptContextTxInfo = + TxInfo + { txInfoInputs = + [ TxInInfo ownInputRef effectInput + , TxInInfo governorInputRef governorInput + ] + , txInfoOutputs = [governorOutput] + , txInfoFee = Value.singleton "" "" 2 + , txInfoMint = burnt + , txInfoDCert = [] + , txInfoWdrl = [] + , txInfoValidRange = Interval.always + , txInfoSignatories = [signer] + , txInfoData = datumPair <$> [governorInputDatum, governorOutputDatum, effectInputDatum] + , txInfoId = "4dae3806cc69615b721d52ed09b758f43f25a8f39b7934d6b28514caf71f5f7b" + } + } From 30b66a29ffb3a215b92f4769b535fa0516772ec5 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 18:49:37 +0800 Subject: [PATCH 14/25] add a simple test --- agora-test/Spec/Effect/GovernorMutation.hs | 28 ++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/agora-test/Spec/Effect/GovernorMutation.hs b/agora-test/Spec/Effect/GovernorMutation.hs index 7863cb6..38b9e38 100644 --- a/agora-test/Spec/Effect/GovernorMutation.hs +++ b/agora-test/Spec/Effect/GovernorMutation.hs @@ -1,6 +1,30 @@ module Spec.Effect.GovernorMutation (tests) where -import Test.Tasty (TestTree) +import Agora.Effect.GovernorMutation (MutateGovernorDatum (..), mutateGovernorValidator) +import Agora.Governor (GovernorDatum (..)) +import Agora.Proposal (ProposalId (..)) +import Plutus.V1.Ledger.Api (TxOutRef (..)) +import Spec.Sample.Effect.GovernorMutation +import Spec.Sample.Shared +import Spec.Util (effectSucceedsWith) +import Test.Tasty (TestTree, testGroup) tests :: [TestTree] -tests = [] +tests = + [ testGroup + "validator" + [ effectSucceedsWith + "Simple" + (mutateGovernorValidator governor) + ( MutateGovernorDatum + { governorRef = TxOutRef "614481d2159bfb72350222d61fce17e548e0fc00e5a1f841ff1837c431346ce7" 1 + , newDatum = + GovernorDatum + { nextProposalId = ProposalId 42 + , proposalThresholds = defaultProposalThresholds + } + } + ) + validContext + ] + ] From ab9f47228766e25d1053e3d0c38ced107afc3490 Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 7 May 2022 18:53:17 +0800 Subject: [PATCH 15/25] fix the broken test --- agora-sample/Sample/Effect/GovernorMutation.hs | 2 +- agora/Agora/Effect/GovernorMutation.hs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs index be6e167..e088abf 100644 --- a/agora-sample/Sample/Effect/GovernorMutation.hs +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -111,7 +111,7 @@ validContext = governorOutput :: TxOut governorOutput = TxOut - { txOutAddress = effectValidatorAddress + { txOutAddress = govValidatorAddress , txOutValue = withMinAda gst , txOutDatumHash = Just $ toDatumHash governorOutputDatum } diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 628f130..11c7629 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -147,7 +147,7 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) let selfAddress = pfield @"address" - #$ mustBePJust # "Self governorInput not found" + #$ mustBePJust # "Self input not found" #$ findTxOutByTxOutRef # txOutRef # txInfo.inputs passert "No output to the effect validator" $ From df8fc484c9ed2b1b37bd2fe0a88b2108737010e5 Mon Sep 17 00:00:00 2001 From: fanghr Date: Mon, 9 May 2022 20:33:21 +0800 Subject: [PATCH 16/25] only allow desired inputs/outputs in an effect tx --- agora/Agora/Effect/GovernorMutation.hs | 61 ++++++++++---------------- 1 file changed, 23 insertions(+), 38 deletions(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 11c7629..18662e0 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -62,8 +62,6 @@ import Agora.Governor.Scripts ( governorSTAssetClassFromGovernor, ) import Agora.Utils ( - findOutputsToAddress, - findTxOutByTxOutRef, mustBePDJust, mustBePJust, passert, @@ -140,62 +138,49 @@ instance PTryFrom PData (PAsData PMutateGovernorDatum) where -} mutateGovernorValidator :: Governor -> ClosedTerm PValidator mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) $ - \_gatCs (datum' :: Term _ PMutateGovernorDatum) txOutRef txInfo' -> P.do + \_gatCs (datum' :: Term _ PMutateGovernorDatum) _ txInfo' -> P.do datum <- pletFields @'["newDatum", "governorRef"] datum' - txInfo <- pletFields @'["mint", "inputs", "outputs", "datums"] txInfo' - let selfAddress = - pfield @"address" - #$ mustBePJust # "Self input not found" - #$ findTxOutByTxOutRef # txOutRef # txInfo.inputs - - passert "No output to the effect validator" $ - pnull #$ findOutputsToAddress # txInfo.outputs # selfAddress - let mint :: Term _ (PBuiltinList _) mint = pto $ pto $ pto $ pfromData txInfo.mint passert "Nothing should be minted/burnt other than GAT" $ plength # mint #== 1 - filteredInputs <- - plet $ - pfilter - # plam - ( \inInfo -> - let value = pfield @"value" #$ pfield @"resolved" # inInfo - in gstValueOf # value #== 1 - ) - # pfromData txInfo.inputs + passert "Only self and governor inputs are allowed" $ + plength # pfromData txInfo.inputs #== 2 - passert "Governor's state token must be moved" $ - plength # filteredInputs #== 1 + let inputWithGST = + mustBePJust # "Governor input not found" #$ pfind + # phoistAcyclic + ( plam $ \inInfo -> + let value = pfield @"value" #$ pfield @"resolved" # inInfo + in gstValueOf # value #== 1 + ) + # pfromData txInfo.inputs - governorInput <- plet $ phead # filteredInputs + govInInfo <- pletFields @'["outRef", "resolved"] $ inputWithGST passert "Can only modify the pinned governor" $ - pfield @"outRef" # governorInput #== datum.governorRef + govInInfo.outRef #== datum.governorRef - let govAddress = - pfield @"address" - #$ pfield @"resolved" - #$ pfromData governorInput + passert "Only governor ouput is allowed" $ + plength # pfromData txInfo.outputs #== 1 - filteredOutputs <- plet $ findOutputsToAddress # pfromData txInfo.outputs # govAddress + let govAddress = pfield @"address" #$ govInInfo.resolved + govOutput' = pfromData $ phead # pfromData txInfo.outputs - passert "Exactly one output to the governor" $ - plength # filteredOutputs #== 1 + govOutput <- pletFields @'["address", "value", "datumHash"] govOutput' - governorOutput <- plet $ phead # filteredOutputs + passert "No output to the governor" $ + govOutput.address #== govAddress - passert "Governor's state token must stay at governor's address" $ - (gstValueOf #$ pfield @"value" # governorOutput) #== 1 + passert "Governor output doesn't carry the GST" $ + gstValueOf # govOutput.value #== 1 let governorOutputDatumHash = - mustBePDJust # "Governor output doesn't have datum" - #$ pfromData - $ pfield @"datumHash" # governorOutput + mustBePDJust # "Governor output doesn't have datum" # govOutput.datumHash governorOutputDatum = pfromData @PGovernorDatum $ mustBePJust # "Governor output datum not found" From 2e21e4c94a5654f6d00aeacbc014ca7c231fb6a2 Mon Sep 17 00:00:00 2001 From: fanghr Date: Tue, 10 May 2022 17:22:15 +0800 Subject: [PATCH 17/25] only allow script inputs from the effect and governor --- agora/Agora/Effect/GovernorMutation.hs | 16 ++++++++++++++-- agora/Agora/Utils.hs | 7 +++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 18662e0..ed224e5 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -62,6 +62,7 @@ import Agora.Governor.Scripts ( governorSTAssetClassFromGovernor, ) import Agora.Utils ( + isScriptAddress, mustBePDJust, mustBePJust, passert, @@ -148,8 +149,19 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) passert "Nothing should be minted/burnt other than GAT" $ plength # mint #== 1 - passert "Only self and governor inputs are allowed" $ - plength # pfromData txInfo.inputs #== 2 + passert "Only self and governor script inputs are allowed" $ + pfoldr + # phoistAcyclic + ( plam $ \inInfo count -> + let address = pfield @"address" #$ pfield @"resolved" # inInfo + in pif + (isScriptAddress # address) + (count + 1) + count + ) + # (0 :: Term _ PInteger) + # pfromData txInfo.inputs + #== 2 let inputWithGST = mustBePJust # "Governor input not found" #$ pfind diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index f37712b..000e788 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -59,6 +59,7 @@ module Agora.Utils ( validatorHashToAddress, pmergeBy, phalve, + isScriptAddress ) where -------------------------------------------------------------------------------- @@ -619,6 +620,12 @@ scriptHashFromAddress = phoistAcyclic $ PScriptCredential ((pfield @"_0" #) -> h) -> pcon $ PJust h _ -> pcon PNothing +isScriptAddress :: Term s (PAddress :--> PBool) +isScriptAddress = phoistAcyclic $ plam $ \addr -> + pmatch (pfromData $ pfield @"credential" # addr) $ \case + PScriptCredential _ -> pconstant True + _ -> pconstant False + -- | Find all TxOuts sent to an Address findOutputsToAddress :: Term s (PBuiltinList (PAsData PTxOut) :--> PAddress :--> PBuiltinList (PAsData PTxOut)) findOutputsToAddress = phoistAcyclic $ From 1e55827d8ba01896890adac9f1338a3c7ed537e1 Mon Sep 17 00:00:00 2001 From: fanghr Date: Mon, 16 May 2022 21:24:43 +0800 Subject: [PATCH 18/25] switch to `TermCont`; fix a bunch of compilation errors; format --- .../Sample/Effect/GovernorMutation.hs | 12 +++++-- agora-test/Spec/Effect/GovernorMutation.hs | 6 ++-- agora/Agora/Effect/GovernorMutation.hs | 31 +++++++++---------- agora/Agora/Utils.hs | 7 +++-- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs index e088abf..b71457f 100644 --- a/agora-sample/Sample/Effect/GovernorMutation.hs +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -31,7 +31,15 @@ import Plutus.V1.Ledger.Api ( import Plutus.V1.Ledger.Api qualified as Interval import Plutus.V1.Ledger.Value (AssetClass, assetClass) import Plutus.V1.Ledger.Value qualified as Value -import Sample.Shared +import Sample.Shared ( + authorityTokenSymbol, + defaultProposalThresholds, + govAssetClass, + govValidatorAddress, + governor, + minAda, + signer, + ) import Test.Util (datumPair, toDatumHash) effectValidator :: Validator @@ -112,7 +120,7 @@ validContext = governorOutput = TxOut { txOutAddress = govValidatorAddress - , txOutValue = withMinAda gst + , txOutValue = mconcat [gst, minAda] , txOutDatumHash = Just $ toDatumHash governorOutputDatum } diff --git a/agora-test/Spec/Effect/GovernorMutation.hs b/agora-test/Spec/Effect/GovernorMutation.hs index 38b9e38..354bf0b 100644 --- a/agora-test/Spec/Effect/GovernorMutation.hs +++ b/agora-test/Spec/Effect/GovernorMutation.hs @@ -4,10 +4,10 @@ import Agora.Effect.GovernorMutation (MutateGovernorDatum (..), mutateGovernorVa import Agora.Governor (GovernorDatum (..)) import Agora.Proposal (ProposalId (..)) import Plutus.V1.Ledger.Api (TxOutRef (..)) -import Spec.Sample.Effect.GovernorMutation -import Spec.Sample.Shared -import Spec.Util (effectSucceedsWith) +import Sample.Effect.GovernorMutation (validContext) +import Sample.Shared (defaultProposalThresholds, governor) import Test.Tasty (TestTree, testGroup) +import Test.Util (effectSucceedsWith) tests :: [TestTree] tests = diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index ed224e5..8e7a9e9 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -38,7 +38,6 @@ import Plutarch.DataRepr ( PIsDataReprInstances (PIsDataReprInstances), ) import Plutarch.Lift (PConstantDecl, PLifted, PUnsafeLiftDecl) -import Plutarch.Monadic qualified as P import Plutarch.TryFrom (PTryFrom (..)) import Plutarch.Unsafe (punsafeCoerce) @@ -65,8 +64,8 @@ import Agora.Utils ( isScriptAddress, mustBePDJust, mustBePJust, - passert, ptryFindDatum, + tcassert, ) -------------------------------------------------------------------------------- @@ -139,17 +138,17 @@ instance PTryFrom PData (PAsData PMutateGovernorDatum) where -} mutateGovernorValidator :: Governor -> ClosedTerm PValidator mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) $ - \_gatCs (datum' :: Term _ PMutateGovernorDatum) _ txInfo' -> P.do - datum <- pletFields @'["newDatum", "governorRef"] datum' - txInfo <- pletFields @'["mint", "inputs", "outputs", "datums"] txInfo' + \_gatCs (datum' :: Term _ PMutateGovernorDatum) _ txInfo' -> unTermCont $ do + datum <- tcont $ pletFields @'["newDatum", "governorRef"] datum' + txInfo <- tcont $ pletFields @'["mint", "inputs", "outputs", "datums"] txInfo' let mint :: Term _ (PBuiltinList _) mint = pto $ pto $ pto $ pfromData txInfo.mint - passert "Nothing should be minted/burnt other than GAT" $ + tcassert "Nothing should be minted/burnt other than GAT" $ plength # mint #== 1 - passert "Only self and governor script inputs are allowed" $ + tcassert "Only self and governor script inputs are allowed" $ pfoldr # phoistAcyclic ( plam $ \inInfo count -> @@ -172,23 +171,23 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) ) # pfromData txInfo.inputs - govInInfo <- pletFields @'["outRef", "resolved"] $ inputWithGST + govInInfo <- tcont $ pletFields @'["outRef", "resolved"] $ inputWithGST - passert "Can only modify the pinned governor" $ + tcassert "Can only modify the pinned governor" $ govInInfo.outRef #== datum.governorRef - passert "Only governor ouput is allowed" $ + tcassert "Only governor ouput is allowed" $ plength # pfromData txInfo.outputs #== 1 let govAddress = pfield @"address" #$ govInInfo.resolved govOutput' = pfromData $ phead # pfromData txInfo.outputs - govOutput <- pletFields @'["address", "value", "datumHash"] govOutput' + govOutput <- tcont $ pletFields @'["address", "value", "datumHash"] govOutput' - passert "No output to the governor" $ + tcassert "No output to the governor" $ govOutput.address #== govAddress - passert "Governor output doesn't carry the GST" $ + tcassert "Governor output doesn't carry the GST" $ gstValueOf # govOutput.value #== 1 let governorOutputDatumHash = @@ -198,10 +197,10 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) mustBePJust # "Governor output datum not found" #$ ptryFindDatum # governorOutputDatumHash # txInfo.datums - passert "Unexpected governor datum" $ datum.newDatum #== governorOutputDatum - passert "New governor datum should be valid" $ governorDatumValid # governorOutputDatum + tcassert "Unexpected governor datum" $ datum.newDatum #== governorOutputDatum + tcassert "New governor datum should be valid" $ governorDatumValid # governorOutputDatum - popaque $ pconstant () + return $ popaque $ pconstant () where gstValueOf :: Term s (PValue :--> PInteger) gstValueOf = phoistAcyclic $ plam $ \v -> pvalueOf # v # pconstant cs # pconstant tn diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 000e788..160d277 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -59,7 +59,7 @@ module Agora.Utils ( validatorHashToAddress, pmergeBy, phalve, - isScriptAddress + isScriptAddress, ) where -------------------------------------------------------------------------------- @@ -621,8 +621,9 @@ scriptHashFromAddress = phoistAcyclic $ _ -> pcon PNothing isScriptAddress :: Term s (PAddress :--> PBool) -isScriptAddress = phoistAcyclic $ plam $ \addr -> - pmatch (pfromData $ pfield @"credential" # addr) $ \case +isScriptAddress = phoistAcyclic $ + plam $ \addr -> + pmatch (pfromData $ pfield @"credential" # addr) $ \case PScriptCredential _ -> pconstant True _ -> pconstant False From b34d6b294dd190cb1e15ea78dfc269b289dc1a29 Mon Sep 17 00:00:00 2001 From: fanghr Date: Thu, 19 May 2022 20:12:24 +0800 Subject: [PATCH 19/25] refactor tests of the effect * test both the effect and governor in the spec * test that the effect and governor will fail when try setting the governor state to a invalid one --- .../Sample/Effect/GovernorMutation.hs | 111 +++++++++++------- agora-sample/Sample/Governor.hs | 2 +- agora-test/Spec/Effect/GovernorMutation.hs | 75 +++++++++--- 3 files changed, 125 insertions(+), 63 deletions(-) diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs index b71457f..bbaf698 100644 --- a/agora-sample/Sample/Effect/GovernorMutation.hs +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -1,9 +1,14 @@ module Sample.Effect.GovernorMutation ( - validContext, + mkEffectTransaction, effectValidator, effectValidatorAddress, effectValidatorHash, atAssetClass, + govRef, + effectRef, + invalidNewGovernorDatum, + validNewGovernorDatum, + mkEffectDatum, ) where import Agora.Effect.GovernorMutation ( @@ -11,14 +16,13 @@ import Agora.Effect.GovernorMutation ( mutateGovernorValidator, ) import Agora.Governor (GovernorDatum (..)) -import Agora.Proposal (ProposalId (..)) +import Agora.Proposal (ProposalId (..), ProposalThresholds (..)) import Plutarch.Api.V1 (mkValidator, validatorHash) +import Plutarch.SafeMoney (Tagged (Tagged)) import Plutus.V1.Ledger.Address (scriptHashAddress) import Plutus.V1.Ledger.Api ( Address, Datum (..), - ScriptContext (..), - ScriptPurpose (Spending), ToData (..), TokenName (..), TxInInfo (..), @@ -42,15 +46,19 @@ import Sample.Shared ( ) import Test.Util (datumPair, toDatumHash) +-- | The effect validator instance. effectValidator :: Validator effectValidator = mkValidator $ mutateGovernorValidator governor +-- | The hash of the validator instance. effectValidatorHash :: ValidatorHash effectValidatorHash = validatorHash effectValidator +-- | The address of the validator. effectValidatorAddress :: Address effectValidatorAddress = scriptHashAddress effectValidatorHash +-- | The assetclass of the authority token. atAssetClass :: AssetClass atAssetClass = assetClass authorityTokenSymbol tokenName where @@ -58,20 +66,36 @@ atAssetClass = assetClass authorityTokenSymbol tokenName ValidatorHash bs = effectValidatorHash tokenName = TokenName bs -validContext :: ScriptContext -validContext = +-- | The mock reference of the governor state UTXO. +govRef :: TxOutRef +govRef = TxOutRef "614481d2159bfb72350222d61fce17e548e0fc00e5a1f841ff1837c431346ce7" 1 + +-- | The mock reference of the effect UTXO. +effectRef :: TxOutRef +effectRef = TxOutRef "c31164dc11835de7eb6187f67d0e1a19c1dfc0786a456923eef5043189cdb578" 1 + +-- | The input effect datum in 'mkEffectTransaction'. +mkEffectDatum :: GovernorDatum -> MutateGovernorDatum +mkEffectDatum newGovDatum = + MutateGovernorDatum + { governorRef = govRef + , newDatum = newGovDatum + } + +{- | Given the new governor state, create an effect to update the governor's state. + + Note that the transaction is valid only if the given new datum is valid. +-} +mkEffectTransaction :: GovernorDatum -> TxInfo +mkEffectTransaction newGovDatum = let gst = Value.assetClassValue govAssetClass 1 at = Value.assetClassValue atAssetClass 1 + -- One authority token is burnt in the process. burnt = Value.assetClassValue atAssetClass (-1) -- - governorInputRef :: TxOutRef - governorInputRef = TxOutRef "614481d2159bfb72350222d61fce17e548e0fc00e5a1f841ff1837c431346ce7" 1 - - -- - governorInputDatum' :: GovernorDatum governorInputDatum' = GovernorDatum @@ -92,21 +116,14 @@ validContext = -- The effect should update 'nextProposalId' effectInputDatum' :: MutateGovernorDatum - effectInputDatum' = - MutateGovernorDatum - { governorRef = governorInputRef - , newDatum = - governorInputDatum' - { nextProposalId = ProposalId 42 - } - } + effectInputDatum' = mkEffectDatum newGovDatum effectInputDatum :: Datum effectInputDatum = Datum $ toBuiltinData effectInputDatum' effectInput :: TxOut effectInput = TxOut { txOutAddress = effectValidatorAddress - , txOutValue = at + , txOutValue = at -- The effect carry an authotity token. , txOutDatumHash = Just $ toDatumHash effectInputDatum } @@ -123,27 +140,35 @@ validContext = , txOutValue = mconcat [gst, minAda] , txOutDatumHash = Just $ toDatumHash governorOutputDatum } - - -- - - ownInputRef :: TxOutRef - ownInputRef = TxOutRef "c31164dc11835de7eb6187f67d0e1a19c1dfc0786a456923eef5043189cdb578" 1 - in ScriptContext - { scriptContextPurpose = Spending ownInputRef - , scriptContextTxInfo = - TxInfo - { txInfoInputs = - [ TxInInfo ownInputRef effectInput - , TxInInfo governorInputRef governorInput - ] - , txInfoOutputs = [governorOutput] - , txInfoFee = Value.singleton "" "" 2 - , txInfoMint = burnt - , txInfoDCert = [] - , txInfoWdrl = [] - , txInfoValidRange = Interval.always - , txInfoSignatories = [signer] - , txInfoData = datumPair <$> [governorInputDatum, governorOutputDatum, effectInputDatum] - , txInfoId = "4dae3806cc69615b721d52ed09b758f43f25a8f39b7934d6b28514caf71f5f7b" - } + in TxInfo + { txInfoInputs = + [ TxInInfo effectRef effectInput + , TxInInfo govRef governorInput + ] + , txInfoOutputs = [governorOutput] + , txInfoFee = Value.singleton "" "" 2 + , txInfoMint = burnt + , txInfoDCert = [] + , txInfoWdrl = [] + , txInfoValidRange = Interval.always + , txInfoSignatories = [signer] + , txInfoData = datumPair <$> [governorInputDatum, governorOutputDatum, effectInputDatum] + , txInfoId = "4dae3806cc69615b721d52ed09b758f43f25a8f39b7934d6b28514caf71f5f7b" } + +validNewGovernorDatum :: GovernorDatum +validNewGovernorDatum = + GovernorDatum + { proposalThresholds = defaultProposalThresholds + , nextProposalId = ProposalId 42 + } + +invalidNewGovernorDatum :: GovernorDatum +invalidNewGovernorDatum = + GovernorDatum + { proposalThresholds = + defaultProposalThresholds + { countVoting = Tagged (-1) + } + , nextProposalId = ProposalId 42 + } diff --git a/agora-sample/Sample/Governor.hs b/agora-sample/Sample/Governor.hs index ff5f0bf..1704035 100644 --- a/agora-sample/Sample/Governor.hs +++ b/agora-sample/Sample/Governor.hs @@ -502,7 +502,7 @@ mintGATs = The effect script should carry an valid tagged authority token, and said token will be burnt in the transaction. We use 'noOpValidator' here as a mock effect, so no actual change is done to the governor state. - TODO: use 'mutateGovernorEffect' as the mock effect in the future. + TODO: use 'Agora.Effect.GovernorMutation.mutateGovernorEffect' as the mock effect in the future. The governor will ensure the new governor state is valid. -} diff --git a/agora-test/Spec/Effect/GovernorMutation.hs b/agora-test/Spec/Effect/GovernorMutation.hs index 354bf0b..207e0b1 100644 --- a/agora-test/Spec/Effect/GovernorMutation.hs +++ b/agora-test/Spec/Effect/GovernorMutation.hs @@ -1,30 +1,67 @@ module Spec.Effect.GovernorMutation (tests) where -import Agora.Effect.GovernorMutation (MutateGovernorDatum (..), mutateGovernorValidator) -import Agora.Governor (GovernorDatum (..)) +import Agora.Effect.GovernorMutation (mutateGovernorValidator) +import Agora.Governor (GovernorDatum (..), GovernorRedeemer (MutateGovernor)) +import Agora.Governor.Scripts (governorValidator) import Agora.Proposal (ProposalId (..)) -import Plutus.V1.Ledger.Api (TxOutRef (..)) -import Sample.Effect.GovernorMutation (validContext) -import Sample.Shared (defaultProposalThresholds, governor) +import Plutus.V1.Ledger.Api (ScriptContext (ScriptContext), ScriptPurpose (Spending)) +import Sample.Effect.GovernorMutation ( + effectRef, + govRef, + invalidNewGovernorDatum, + mkEffectDatum, + mkEffectTransaction, + validNewGovernorDatum, + ) +import Sample.Shared qualified as Shared import Test.Tasty (TestTree, testGroup) -import Test.Util (effectSucceedsWith) +import Test.Util (effectFailsWith, effectSucceedsWith, validatorFailsWith, validatorSucceedsWith) tests :: [TestTree] tests = [ testGroup "validator" - [ effectSucceedsWith - "Simple" - (mutateGovernorValidator governor) - ( MutateGovernorDatum - { governorRef = TxOutRef "614481d2159bfb72350222d61fce17e548e0fc00e5a1f841ff1837c431346ce7" 1 - , newDatum = - GovernorDatum - { nextProposalId = ProposalId 42 - , proposalThresholds = defaultProposalThresholds - } - } - ) - validContext + [ testGroup + "valid new governor datum" + [ validatorSucceedsWith + "governor" + (governorValidator Shared.governor) + ( GovernorDatum + { proposalThresholds = Shared.defaultProposalThresholds + , nextProposalId = ProposalId 0 + } + ) + MutateGovernor + ( ScriptContext + (mkEffectTransaction validNewGovernorDatum) + (Spending govRef) + ) + , effectSucceedsWith + "effect" + (mutateGovernorValidator Shared.governor) + (mkEffectDatum validNewGovernorDatum) + (ScriptContext (mkEffectTransaction validNewGovernorDatum) (Spending effectRef)) + ] + , testGroup + "invalid new governor datum" + [ validatorFailsWith + "governor" + (governorValidator Shared.governor) + ( GovernorDatum + { proposalThresholds = Shared.defaultProposalThresholds + , nextProposalId = ProposalId 0 + } + ) + MutateGovernor + ( ScriptContext + (mkEffectTransaction invalidNewGovernorDatum) + (Spending govRef) + ) + , effectFailsWith + "effect" + (mutateGovernorValidator Shared.governor) + (mkEffectDatum validNewGovernorDatum) + (ScriptContext (mkEffectTransaction invalidNewGovernorDatum) (Spending effectRef)) + ] ] ] From ab3dfba6e0d621ef62c7a8cf36513d38cb23bb08 Mon Sep 17 00:00:00 2001 From: fanghr Date: Thu, 19 May 2022 21:03:42 +0800 Subject: [PATCH 20/25] add missing docs && consistent naming --- agora/Agora/Effect/GovernorMutation.hs | 30 +++++++++++++++----------- agora/Agora/Utils.hs | 1 + 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 8e7a9e9..4b929f2 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -138,16 +138,17 @@ instance PTryFrom PData (PAsData PMutateGovernorDatum) where -} mutateGovernorValidator :: Governor -> ClosedTerm PValidator mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) $ - \_gatCs (datum' :: Term _ PMutateGovernorDatum) _ txInfo' -> unTermCont $ do - datum <- tcont $ pletFields @'["newDatum", "governorRef"] datum' - txInfo <- tcont $ pletFields @'["mint", "inputs", "outputs", "datums"] txInfo' + \_gatCs (datum :: Term _ PMutateGovernorDatum) _ txInfo -> unTermCont $ do + datumF <- tcont $ pletFields @'["newDatum", "governorRef"] datum + txInfoF <- tcont $ pletFields @'["mint", "inputs", "outputs", "datums"] txInfo let mint :: Term _ (PBuiltinList _) - mint = pto $ pto $ pto $ pfromData txInfo.mint + mint = pto $ pto $ pto $ pfromData txInfoF.mint tcassert "Nothing should be minted/burnt other than GAT" $ plength # mint #== 1 + -- Only two script inputs are alloed: one from the effect, one from the governor. tcassert "Only self and governor script inputs are allowed" $ pfoldr # phoistAcyclic @@ -159,9 +160,10 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) count ) # (0 :: Term _ PInteger) - # pfromData txInfo.inputs + # pfromData txInfoF.inputs #== 2 + -- Find the governor input by looking for GST. let inputWithGST = mustBePJust # "Governor input not found" #$ pfind # phoistAcyclic @@ -169,18 +171,20 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) let value = pfield @"value" #$ pfield @"resolved" # inInfo in gstValueOf # value #== 1 ) - # pfromData txInfo.inputs + # pfromData txInfoF.inputs govInInfo <- tcont $ pletFields @'["outRef", "resolved"] $ inputWithGST + -- The effect can only modify the governor UTXO referenced in the datum. tcassert "Can only modify the pinned governor" $ - govInInfo.outRef #== datum.governorRef + govInInfo.outRef #== datumF.governorRef - tcassert "Only governor ouput is allowed" $ - plength # pfromData txInfo.outputs #== 1 + -- The transaction can only have one output, which should be sent to the governor. + tcassert "Only governor output is allowed" $ + plength # pfromData txInfoF.outputs #== 1 let govAddress = pfield @"address" #$ govInInfo.resolved - govOutput' = pfromData $ phead # pfromData txInfo.outputs + govOutput' = pfromData $ phead # pfromData txInfoF.outputs govOutput <- tcont $ pletFields @'["address", "value", "datumHash"] govOutput' @@ -195,13 +199,15 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov) governorOutputDatum = pfromData @PGovernorDatum $ mustBePJust # "Governor output datum not found" - #$ ptryFindDatum # governorOutputDatumHash # txInfo.datums + #$ ptryFindDatum # governorOutputDatumHash # txInfoF.datums - tcassert "Unexpected governor datum" $ datum.newDatum #== governorOutputDatum + -- Ensure the output governor datum is what we want. + tcassert "Unexpected governor datum" $ datumF.newDatum #== governorOutputDatum tcassert "New governor datum should be valid" $ governorDatumValid # governorOutputDatum return $ popaque $ pconstant () where + -- Get the amount of GST in the a given value. gstValueOf :: Term s (PValue :--> PInteger) gstValueOf = phoistAcyclic $ plam $ \v -> pvalueOf # v # pconstant cs # pconstant tn where diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 160d277..63cf022 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -620,6 +620,7 @@ scriptHashFromAddress = phoistAcyclic $ PScriptCredential ((pfield @"_0" #) -> h) -> pcon $ PJust h _ -> pcon PNothing +-- | Return true if the given address is a script address. isScriptAddress :: Term s (PAddress :--> PBool) isScriptAddress = phoistAcyclic $ plam $ \addr -> From dba8b3c68b59f97f774e908ab3eb46e8eef0767c Mon Sep 17 00:00:00 2001 From: fanghr Date: Fri, 20 May 2022 18:22:33 +0800 Subject: [PATCH 21/25] add `isPubKey` && utilize it in the `TreasuryWithdrawal` effect --- agora/Agora/Effect/TreasuryWithdrawal.hs | 10 ++-------- agora/Agora/Utils.hs | 14 ++++++++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/agora/Agora/Effect/TreasuryWithdrawal.hs b/agora/Agora/Effect/TreasuryWithdrawal.hs index 6bb2851..5bf451c 100644 --- a/agora/Agora/Effect/TreasuryWithdrawal.hs +++ b/agora/Agora/Effect/TreasuryWithdrawal.hs @@ -18,7 +18,7 @@ import GHC.Generics qualified as GHC import Generics.SOP (Generic, I (I)) import Agora.Effect (makeEffect) -import Agora.Utils (findTxOutByTxOutRef, paddValue, tcassert, tclet, tcmatch) +import Agora.Utils (findTxOutByTxOutRef, isPubKey, paddValue, tcassert, tclet, tcmatch) import Plutarch.Api.V1 ( PCredential (..), PTuple, @@ -140,12 +140,6 @@ treasuryWithdrawalValidator currSymbol = makeEffect currSymbol $ treasuryInputValuesSum = sumValues #$ ofTreasury # inputValues treasuryOutputValuesSum = sumValues #$ ofTreasury # outputValues receiverValuesSum = sumValues # datum.receivers - isPubkey = plam $ \cred -> - pmatch cred $ - \case - PPubKeyCredential _ -> pcon PTrue - PScriptCredential _ -> pcon PFalse - -- Constraints outputContentMatchesRecivers = pall # plam (\out -> pelem # out # outputValues) @@ -165,7 +159,7 @@ treasuryWithdrawalValidator currSymbol = makeEffect currSymbol $ ( \((pfield @"_0" #) . pfromData -> cred) -> cred #== pfield @"credential" # effInput.address #|| pelem # cred # datum.treasuries - #|| isPubkey # pfromData cred + #|| isPubKey # pfromData cred ) # inputValues diff --git a/agora/Agora/Utils.hs b/agora/Agora/Utils.hs index 63cf022..1a6424b 100644 --- a/agora/Agora/Utils.hs +++ b/agora/Agora/Utils.hs @@ -60,6 +60,7 @@ module Agora.Utils ( pmergeBy, phalve, isScriptAddress, + isPubKey, ) where -------------------------------------------------------------------------------- @@ -623,10 +624,15 @@ scriptHashFromAddress = phoistAcyclic $ -- | Return true if the given address is a script address. isScriptAddress :: Term s (PAddress :--> PBool) isScriptAddress = phoistAcyclic $ - plam $ \addr -> - pmatch (pfromData $ pfield @"credential" # addr) $ \case - PScriptCredential _ -> pconstant True - _ -> pconstant False + plam $ \addr -> pnot #$ isPubKey #$ pfromData $ pfield @"credential" # addr + +-- | Return true if the given credential is a pub-key-hash. +isPubKey :: Term s (PCredential :--> PBool) +isPubKey = phoistAcyclic $ + plam $ \cred -> + pmatch cred $ \case + PScriptCredential _ -> pconstant False + _ -> pconstant True -- | Find all TxOuts sent to an Address findOutputsToAddress :: Term s (PBuiltinList (PAsData PTxOut) :--> PAddress :--> PBuiltinList (PAsData PTxOut)) From 272be9f1f5a243559d56949ddb365cc69f122ee8 Mon Sep 17 00:00:00 2001 From: fanghr Date: Fri, 20 May 2022 19:10:34 +0800 Subject: [PATCH 22/25] better naming --- agora-sample/Sample/Effect/GovernorMutation.hs | 6 +++--- agora-test/Spec/Effect/GovernorMutation.hs | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs index bbaf698..7d41cb7 100644 --- a/agora-sample/Sample/Effect/GovernorMutation.hs +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -1,5 +1,5 @@ module Sample.Effect.GovernorMutation ( - mkEffectTransaction, + mkEffectTxInfo, effectValidator, effectValidatorAddress, effectValidatorHash, @@ -86,8 +86,8 @@ mkEffectDatum newGovDatum = Note that the transaction is valid only if the given new datum is valid. -} -mkEffectTransaction :: GovernorDatum -> TxInfo -mkEffectTransaction newGovDatum = +mkEffectTxInfo :: GovernorDatum -> TxInfo +mkEffectTxInfo newGovDatum = let gst = Value.assetClassValue govAssetClass 1 at = Value.assetClassValue atAssetClass 1 diff --git a/agora-test/Spec/Effect/GovernorMutation.hs b/agora-test/Spec/Effect/GovernorMutation.hs index 207e0b1..1436b5a 100644 --- a/agora-test/Spec/Effect/GovernorMutation.hs +++ b/agora-test/Spec/Effect/GovernorMutation.hs @@ -10,7 +10,7 @@ import Sample.Effect.GovernorMutation ( govRef, invalidNewGovernorDatum, mkEffectDatum, - mkEffectTransaction, + mkEffectTxInfo, validNewGovernorDatum, ) import Sample.Shared qualified as Shared @@ -24,7 +24,7 @@ tests = [ testGroup "valid new governor datum" [ validatorSucceedsWith - "governor" + "governor validator should pass" (governorValidator Shared.governor) ( GovernorDatum { proposalThresholds = Shared.defaultProposalThresholds @@ -33,19 +33,19 @@ tests = ) MutateGovernor ( ScriptContext - (mkEffectTransaction validNewGovernorDatum) + (mkEffectTxInfo validNewGovernorDatum) (Spending govRef) ) , effectSucceedsWith - "effect" + "effect validator should pass" (mutateGovernorValidator Shared.governor) (mkEffectDatum validNewGovernorDatum) - (ScriptContext (mkEffectTransaction validNewGovernorDatum) (Spending effectRef)) + (ScriptContext (mkEffectTxInfo validNewGovernorDatum) (Spending effectRef)) ] , testGroup "invalid new governor datum" [ validatorFailsWith - "governor" + "governor validator should fail" (governorValidator Shared.governor) ( GovernorDatum { proposalThresholds = Shared.defaultProposalThresholds @@ -54,14 +54,14 @@ tests = ) MutateGovernor ( ScriptContext - (mkEffectTransaction invalidNewGovernorDatum) + (mkEffectTxInfo invalidNewGovernorDatum) (Spending govRef) ) , effectFailsWith - "effect" + "effect validator should fail" (mutateGovernorValidator Shared.governor) (mkEffectDatum validNewGovernorDatum) - (ScriptContext (mkEffectTransaction invalidNewGovernorDatum) (Spending effectRef)) + (ScriptContext (mkEffectTxInfo invalidNewGovernorDatum) (Spending effectRef)) ] ] ] From 1ba572240931b7b470c45cb83a9f89d37f1061cc Mon Sep 17 00:00:00 2001 From: Emily Martins Date: Fri, 20 May 2022 17:03:41 +0200 Subject: [PATCH 23/25] init `agora-scripts` for generating ScriptInfo for CTL --- agora-scripts/Options.hs | 45 +++++++++++ agora-scripts/Scripts.hs | 66 ++++++++++++++++ agora.cabal | 35 ++++++--- agora/Agora/Aeson/Orphans.hs | 146 +++++++++++++++++++++++++++++++++++ agora/Agora/SafeMoney.hs | 14 +++- agora/Agora/ScriptInfo.hs | 59 ++++++++++++++ 6 files changed, 353 insertions(+), 12 deletions(-) create mode 100644 agora-scripts/Options.hs create mode 100644 agora-scripts/Scripts.hs create mode 100644 agora/Agora/Aeson/Orphans.hs create mode 100644 agora/Agora/ScriptInfo.hs diff --git a/agora-scripts/Options.hs b/agora-scripts/Options.hs new file mode 100644 index 0000000..f6c4d10 --- /dev/null +++ b/agora-scripts/Options.hs @@ -0,0 +1,45 @@ +{- | +Module : Options +Maintainer : emi@haskell.fyi +Description: Command line options for 'agora-scripts'. + +Command line options for 'agora-scripts'. +-} +module Options (Options (..), parseOptions) where + +import Options.Applicative ((<**>)) +import Options.Applicative qualified as Opt + +data Options = Options + { config :: FilePath + , output :: FilePath + } + deriving stock (Show, Eq) + +opt :: Opt.Parser Options +opt = + Options + <$> Opt.strOption + ( Opt.long "config" + <> Opt.short 'c' + <> Opt.metavar "CONFIG_PATH" + <> Opt.value "./" + <> Opt.help "The path where the script configuration is." + ) + <*> Opt.strOption + ( Opt.long "output" + <> Opt.short 'o' + <> Opt.metavar "OUTPUT_PATH" + <> Opt.value "./" + <> Opt.help "Output where generated scripts will be." + ) + +parseOptions :: IO Options +parseOptions = Opt.execParser p + where + p = + Opt.info + (opt <**> Opt.helper) + ( Opt.fullDesc + <> Opt.progDesc "Generate Agora scripts for off-chain use." + ) diff --git a/agora-scripts/Scripts.hs b/agora-scripts/Scripts.hs new file mode 100644 index 0000000..7d171d1 --- /dev/null +++ b/agora-scripts/Scripts.hs @@ -0,0 +1,66 @@ +{- | +Module : Scripts +Maintainer : emi@haskell.fyi +Description: Export scripts given configuration. + +Export scripts given configuration. +-} +module Scripts (main) where + +import Agora.Governor (Governor (Governor)) +import Agora.Governor qualified as Governor +import Agora.Governor.Scripts (governorPolicy) +import Agora.SafeMoney (GTTag) +import Agora.ScriptInfo (PolicyInfo, mkPolicyInfo) +import Control.Monad ((>=>)) +import Data.Aeson qualified as Aeson +import GHC.Generics qualified as GHC +import Options (Options (..), parseOptions) +import Plutarch.SafeMoney (Tagged) +import Plutus.V1.Ledger.Api (TxOutRef) +import Plutus.V1.Ledger.Value (AssetClass) +import System.Exit (exitFailure) + +data ScriptsConfig = ScriptsConfig + { governorInitialSpend :: TxOutRef + , gtClassRef :: Tagged GTTag AssetClass + , maximumCosigners :: Integer + } + deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) + deriving stock (Show, Eq, GHC.Generic) + +data AgoraScripts = AgoraScripts + { governorPolicyInfo :: PolicyInfo + } + deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) + deriving stock (Show, Eq, GHC.Generic) + +main :: IO () +main = do + putStrLn "Hello, world!" + + options <- parseOptions + + params <- + Aeson.eitherDecodeFileStrict @ScriptsConfig options.config + >>= either (putStrLn >=> const exitFailure) pure + + let scripts = agoraScripts params + + print params + print scripts + + pure () + +agoraScripts :: ScriptsConfig -> AgoraScripts +agoraScripts config = + AgoraScripts + { governorPolicyInfo = mkPolicyInfo (governorPolicy governor) + } + where + governor = + Governor + { Governor.gstOutRef = config.governorInitialSpend + , Governor.gtClassRef = config.gtClassRef + , Governor.maximumCosigners = config.maximumCosigners + } diff --git a/agora.cabal b/agora.cabal index 7d01530..be3d748 100644 --- a/agora.cabal +++ b/agora.cabal @@ -146,18 +146,21 @@ library Agora.Utils Agora.Utils.Value + Agora.ScriptInfo + Agora.Aeson.Orphans + other-modules: hs-source-dirs: agora library pprelude + default-language: Haskell2010 + exposed-modules: PPrelude + hs-source-dirs: agora + build-depends: , base , plutarch - exposed-modules: PPrelude - hs-source-dirs: agora - default-language: Haskell2010 - library agora-testlib import: lang, deps, test-deps exposed-modules: Test.Util @@ -165,7 +168,6 @@ library agora-testlib library agora-sample import: lang, deps, test-deps - build-depends: agora-testlib exposed-modules: Sample.Effect.TreasuryWithdrawal Sample.Governor @@ -173,9 +175,10 @@ library agora-sample Sample.Shared Sample.Stake Sample.Treasury - hs-source-dirs: agora-sample + build-depends: agora-testlib + test-suite agora-test import: lang, deps, test-deps type: exitcode-stdio-1.0 @@ -205,16 +208,26 @@ benchmark agora-bench , agora , agora-sample +executable agora-scripts + import: lang, deps, exe-opts + main-is: Scripts.hs + hs-source-dirs: agora-scripts + other-modules: + Options + build-depends: + , agora + , optparse-applicative + executable agora-purescript-bridge import: lang, deps, exe-opts main-is: Bridge.hs + hs-source-dirs: agora-purescript-bridge + other-modules: + AgoraTypes + Options + build-depends: , agora , optparse-applicative , path , purescript-bridge - - hs-source-dirs: agora-purescript-bridge - other-modules: - AgoraTypes - Options diff --git a/agora/Agora/Aeson/Orphans.hs b/agora/Agora/Aeson/Orphans.hs new file mode 100644 index 0000000..522643a --- /dev/null +++ b/agora/Agora/Aeson/Orphans.hs @@ -0,0 +1,146 @@ +{-# OPTIONS_GHC -Wno-orphans #-} + +module Agora.Aeson.Orphans (AsBase16Bytes (..)) where + +-------------------------------------------------------------------------------- + +import Data.Coerce (Coercible, coerce) +import Prelude + +-------------------------------------------------------------------------------- + +import Codec.Serialise qualified as Codec +import Data.Aeson qualified as Aeson +import Data.Aeson.Types qualified as Aeson +import Data.ByteString.Lazy qualified as Lazy +import Data.Text qualified as T +import Data.Text.Encoding qualified as T + +-------------------------------------------------------------------------------- + +import Plutus.V1.Ledger.Api qualified as Plutus +import Plutus.V1.Ledger.Bytes qualified as Plutus +import Plutus.V1.Ledger.Value qualified as Plutus + +-------------------------------------------------------------------------------- + +newtype AsBase16Bytes a = AsBase16Bytes {unAsBase16Bytes :: a} +newtype AsBase16Codec a = AsBase16Codec {unAsBase16Codec :: a} + +deriving via + (Plutus.CurrencySymbol, Plutus.TokenName) + instance + Aeson.ToJSON Plutus.AssetClass + +deriving via + (Plutus.CurrencySymbol, Plutus.TokenName) + instance + Aeson.FromJSON Plutus.AssetClass + +deriving via + AsBase16Bytes Plutus.TxId + instance + Aeson.FromJSON Plutus.TxId + +deriving via + AsBase16Bytes Plutus.TxId + instance + Aeson.ToJSON Plutus.TxId + +deriving anyclass instance Aeson.FromJSON Plutus.TxOutRef +deriving anyclass instance Aeson.ToJSON Plutus.TxOutRef + +instance (Coercible a Plutus.LedgerBytes) => Aeson.ToJSON (AsBase16Bytes a) where + toJSON = + Aeson.String + . Plutus.encodeByteString + . Plutus.bytes + . coerce @(AsBase16Bytes a) @Plutus.LedgerBytes + +instance (Coercible Plutus.LedgerBytes a) => Aeson.FromJSON (AsBase16Bytes a) where + parseJSON v = + Aeson.parseJSON @T.Text v + >>= either (Aeson.parserThrowError []) (pure . coerce @_ @(AsBase16Bytes a)) + . Plutus.fromHex + . T.encodeUtf8 + +instance (Codec.Serialise a) => Aeson.ToJSON (AsBase16Codec a) where + toJSON = + Aeson.String + . Plutus.encodeByteString + . Lazy.toStrict + . Codec.serialise @a + . (.unAsBase16Codec) + +instance (Codec.Serialise a) => Aeson.FromJSON (AsBase16Codec a) where + parseJSON v = + Aeson.parseJSON @T.Text v + >>= either (Aeson.parserThrowError [] . show) (pure . AsBase16Codec) + . Codec.deserialiseOrFail + . Lazy.fromStrict + . T.encodeUtf8 + +-------------------------------------------------------------------------------- + +deriving via + (AsBase16Bytes Plutus.CurrencySymbol) + instance + (Aeson.ToJSON Plutus.CurrencySymbol) +deriving via + (AsBase16Bytes Plutus.CurrencySymbol) + instance + (Aeson.FromJSON Plutus.CurrencySymbol) + +deriving via + (AsBase16Bytes Plutus.TokenName) + instance + (Aeson.ToJSON Plutus.TokenName) +deriving via + (AsBase16Bytes Plutus.TokenName) + instance + (Aeson.FromJSON Plutus.TokenName) + +deriving via + (AsBase16Bytes Plutus.ValidatorHash) + instance + (Aeson.ToJSON Plutus.ValidatorHash) +deriving via + (AsBase16Bytes Plutus.ValidatorHash) + instance + (Aeson.FromJSON Plutus.ValidatorHash) + +deriving via + (AsBase16Codec Plutus.Validator) + instance + (Aeson.ToJSON Plutus.Validator) +deriving via + (AsBase16Codec Plutus.Validator) + instance + (Aeson.FromJSON Plutus.Validator) + +deriving via + (AsBase16Codec Plutus.MintingPolicy) + instance + (Aeson.ToJSON Plutus.MintingPolicy) +deriving via + (AsBase16Codec Plutus.MintingPolicy) + instance + (Aeson.FromJSON Plutus.MintingPolicy) + +deriving via + (AsBase16Codec Plutus.Script) + instance + (Aeson.ToJSON Plutus.Script) +deriving via + (AsBase16Codec Plutus.Script) + instance + (Aeson.FromJSON Plutus.Script) + +deriving via + Integer + instance + (Aeson.ToJSON Plutus.POSIXTime) +deriving via + Integer + instance + (Aeson.FromJSON Plutus.POSIXTime) diff --git a/agora/Agora/SafeMoney.hs b/agora/Agora/SafeMoney.hs index f94ae8d..2a469ea 100644 --- a/agora/Agora/SafeMoney.hs +++ b/agora/Agora/SafeMoney.hs @@ -8,6 +8,9 @@ Tags and extras for "Plutarch.SafeMoney". module Agora.SafeMoney ( ADATag, GTTag, + GovernorSTTag, + StakeSTTag, + ProposalSTTag, adaRef, ) where @@ -18,7 +21,7 @@ import Plutus.V1.Ledger.Value (AssetClass (AssetClass)) import Plutarch.SafeMoney -------------------------------------------------------------------------------- --- Example tags +-- Tags -- | Governance token. data GTTag @@ -26,6 +29,15 @@ data GTTag -- | ADA. data ADATag +-- | Governor ST token. +data GovernorSTTag + +-- | Stake ST token. +data StakeSTTag + +-- | Proposal ST token. +data ProposalSTTag + -------------------------------------------------------------------------------- -- | Resolves ada tags. diff --git a/agora/Agora/ScriptInfo.hs b/agora/Agora/ScriptInfo.hs new file mode 100644 index 0000000..54a709e --- /dev/null +++ b/agora/Agora/ScriptInfo.hs @@ -0,0 +1,59 @@ +{- | +Module : Agora.ScriptInfo +Maintainer : emi@haskell.fyi +Description: Exportable script bundles for off-chain consumption. + +Exportable script bundles for off-chain consumption. +-} +module Agora.ScriptInfo ( + -- * Types + PolicyInfo (..), + ValidatorInfo (..), + + -- * Introduction functions + mkValidatorInfo, + mkPolicyInfo, +) where + +import Agora.Aeson.Orphans () +import Data.Aeson qualified as Aeson +import GHC.Generics qualified as GHC +import Plutarch.Api.V1 (PMintingPolicy, PValidator, mintingPolicySymbol, mkMintingPolicy, mkValidator, validatorHash) +import Plutus.V1.Ledger.Api (MintingPolicy, Validator, ValidatorHash) +import Plutus.V1.Ledger.Value (CurrencySymbol) + +-- | Bundle containing a 'Validator' and its hash. +data ValidatorInfo = ValidatorInfo + { script :: Validator + , hash :: ValidatorHash + } + deriving stock (Show, Eq, GHC.Generic) + deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) + +-- | Create a 'ValidatorInfo' given a Plutarch term. +mkValidatorInfo :: ClosedTerm PValidator -> ValidatorInfo +mkValidatorInfo term = + ValidatorInfo + { script = validator + , hash = validatorHash validator + } + where + validator = mkValidator term + +-- | Bundle containing a 'MintingPolicy' and its symbol. +data PolicyInfo = PolicyInfo + { policy :: MintingPolicy + , currencySymbol :: CurrencySymbol + } + deriving stock (Show, Eq, GHC.Generic) + deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) + +-- | Create a 'PolicyInfo' given a Plutarch term. +mkPolicyInfo :: ClosedTerm PMintingPolicy -> PolicyInfo +mkPolicyInfo term = + PolicyInfo + { policy = policy + , currencySymbol = mintingPolicySymbol policy + } + where + policy = mkMintingPolicy term From effbcd1d6b51b33b4ca1f46351918b2c473c5d92 Mon Sep 17 00:00:00 2001 From: Emily Martins Date: Fri, 20 May 2022 18:08:31 +0200 Subject: [PATCH 24/25] add remaining scripts, export to json file, fix compile --- agora-scripts/Options.hs | 4 +- agora-scripts/Scripts.hs | 79 +++++++++++++++++++++++++------- agora-scripts/agora-params.json | 11 +++++ agora-scripts/agora-scripts.json | 1 + agora.cabal | 3 +- agora/Agora/ScriptInfo.hs | 4 ++ agora/Agora/Treasury.hs | 1 + 7 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 agora-scripts/agora-params.json create mode 100644 agora-scripts/agora-scripts.json diff --git a/agora-scripts/Options.hs b/agora-scripts/Options.hs index f6c4d10..e56d09a 100644 --- a/agora-scripts/Options.hs +++ b/agora-scripts/Options.hs @@ -23,14 +23,14 @@ opt = ( Opt.long "config" <> Opt.short 'c' <> Opt.metavar "CONFIG_PATH" - <> Opt.value "./" + <> Opt.value "./agora-scripts/agora-params.json" <> Opt.help "The path where the script configuration is." ) <*> Opt.strOption ( Opt.long "output" <> Opt.short 'o' <> Opt.metavar "OUTPUT_PATH" - <> Opt.value "./" + <> Opt.value "./agora-scripts/agora-scripts.json" <> Opt.help "Output where generated scripts will be." ) diff --git a/agora-scripts/Scripts.hs b/agora-scripts/Scripts.hs index 7d171d1..0544a1c 100644 --- a/agora-scripts/Scripts.hs +++ b/agora-scripts/Scripts.hs @@ -5,23 +5,40 @@ Description: Export scripts given configuration. Export scripts given configuration. -} -module Scripts (main) where +module Main (main) where +import Agora.AuthorityToken (AuthorityToken, authorityTokenPolicy) import Agora.Governor (Governor (Governor)) import Agora.Governor qualified as Governor -import Agora.Governor.Scripts (governorPolicy) +import Agora.Governor.Scripts ( + authorityTokenFromGovernor, + authorityTokenSymbolFromGovernor, + governorPolicy, + governorValidator, + proposalFromGovernor, + stakeFromGovernor, + ) +import Agora.Proposal (Proposal) +import Agora.Proposal.Scripts (proposalPolicy, proposalValidator) import Agora.SafeMoney (GTTag) -import Agora.ScriptInfo (PolicyInfo, mkPolicyInfo) +import Agora.ScriptInfo (PolicyInfo, ValidatorInfo, mkPolicyInfo, mkValidatorInfo) +import Agora.Stake (Stake) +import Agora.Stake.Scripts (stakePolicy, stakeValidator) +import Agora.Treasury (treasuryValidator) import Control.Monad ((>=>)) import Data.Aeson qualified as Aeson import GHC.Generics qualified as GHC import Options (Options (..), parseOptions) +import Plutarch.Api.V1 (mintingPolicySymbol, mkMintingPolicy) import Plutarch.SafeMoney (Tagged) import Plutus.V1.Ledger.Api (TxOutRef) -import Plutus.V1.Ledger.Value (AssetClass) +import Plutus.V1.Ledger.Value (AssetClass, CurrencySymbol) +import Plutus.V1.Ledger.Value qualified as Value import System.Exit (exitFailure) +import Text.Printf (printf) -data ScriptsConfig = ScriptsConfig +-- | Params required for creating script export. +data ScriptParams = ScriptParams { governorInitialSpend :: TxOutRef , gtClassRef :: Tagged GTTag AssetClass , maximumCosigners :: Integer @@ -29,38 +46,68 @@ data ScriptsConfig = ScriptsConfig deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) deriving stock (Show, Eq, GHC.Generic) +-- | Scripts that get exported. data AgoraScripts = AgoraScripts { governorPolicyInfo :: PolicyInfo + , governorValidatorInfo :: ValidatorInfo + , stakePolicyInfo :: PolicyInfo + , stakeValidatorInfo :: ValidatorInfo + , proposalPolicyInfo :: PolicyInfo + , proposalValidatorInfo :: ValidatorInfo + , treasuryValidatorInfo :: ValidatorInfo + , authorityTokenPolicyInfo :: PolicyInfo } deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) deriving stock (Show, Eq, GHC.Generic) main :: IO () main = do - putStrLn "Hello, world!" - options <- parseOptions params <- - Aeson.eitherDecodeFileStrict @ScriptsConfig options.config + Aeson.eitherDecodeFileStrict @ScriptParams options.config >>= either (putStrLn >=> const exitFailure) pure let scripts = agoraScripts params - print params - print scripts + Aeson.encodeFile options.output scripts - pure () + printf "Done! Wrote to %s\n" options.output -agoraScripts :: ScriptsConfig -> AgoraScripts -agoraScripts config = +-- | Create scripts from params. +agoraScripts :: ScriptParams -> AgoraScripts +agoraScripts params = AgoraScripts { governorPolicyInfo = mkPolicyInfo (governorPolicy governor) + , governorValidatorInfo = mkValidatorInfo (governorValidator governor) + , stakePolicyInfo = mkPolicyInfo (stakePolicy params.gtClassRef) + , stakeValidatorInfo = mkValidatorInfo (stakeValidator stake) + , proposalPolicyInfo = mkPolicyInfo (proposalPolicy governorSTAssetClass) + , proposalValidatorInfo = mkValidatorInfo (proposalValidator proposal) + , treasuryValidatorInfo = mkValidatorInfo (treasuryValidator authorityTokenSymbol) + , authorityTokenPolicyInfo = mkPolicyInfo (authorityTokenPolicy authorityToken) } where + governor :: Governor governor = Governor - { Governor.gstOutRef = config.governorInitialSpend - , Governor.gtClassRef = config.gtClassRef - , Governor.maximumCosigners = config.maximumCosigners + { Governor.gstOutRef = params.governorInitialSpend + , Governor.gtClassRef = params.gtClassRef + , Governor.maximumCosigners = params.maximumCosigners } + + authorityToken :: AuthorityToken + authorityToken = authorityTokenFromGovernor governor + + authorityTokenSymbol :: CurrencySymbol + authorityTokenSymbol = authorityTokenSymbolFromGovernor governor + + governorSTAssetClass :: AssetClass + governorSTAssetClass = + Value.assetClass (mintingPolicySymbol $ mkMintingPolicy $ governorPolicy governor) "" + + proposal :: Proposal + proposal = proposalFromGovernor governor + + stake :: Stake + stake = stakeFromGovernor governor diff --git a/agora-scripts/agora-params.json b/agora-scripts/agora-params.json new file mode 100644 index 0000000..cb036a3 --- /dev/null +++ b/agora-scripts/agora-params.json @@ -0,0 +1,11 @@ +{ + "governorInitialSpend": { + "txOutRefId": "0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88be", + "txOutRefIdx": 0 + }, + "gtClassRef": [ + "", + "" + ], + "maximumCosigners": 5 +} diff --git a/agora-scripts/agora-scripts.json b/agora-scripts/agora-scripts.json new file mode 100644 index 0000000..d02a671 --- /dev/null +++ b/agora-scripts/agora-scripts.json @@ -0,0 +1 @@ +{"authorityTokenPolicyInfo":{"currencySymbol":"6aa44a4ea34725d9bcf9b522babe6b6b94ae55eddac23b9ccaa94427","policy":"5904ad010000323232323232323232323232323232323232323222323232323253330153370e90000010a99980a99b8848000cc88c8ccc02c00cdd7180e0009bae301c301b001301c00137566032601e6030008664466e9520003300e37520046601c6ea400403cdd7180c8008070a99980a999119b8848000ccc88c054894ccc060004400c4cc010c07c004c008c07800488cdc00009991191998078019bae3020001375c6040603e00260400026eacc074c070c078c8c078c074004c078008011200000133223374a9000198071ba90023300e375200201e91011c3f57878004c69a4ebcad6907b12e8245e44fd85ebaff8c27dd9c2f4b0000e375860320082a66602a6644646602646464646464a66603c66e1d2000002133332233333301c22533301f0011225001153330223371e646eb8c09cc0a0004c098004010488c008c0a000c4c008c094004004888c008c09cc098c0a000c4894004888c00800c4894004dd718110009bac302232302230223022302230190013021007233330090073756604600a604600c002294054cc07d2401455061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5574696c732e68733a3536333a31352d323300163023002301e0013754603e603c002603a002603c0026eb0c070004c068c070008c0640148888cc88c8cccc88cccc068894ccc074004489400454ccc080cdd798111812000802091180118130018980118118008009111801181380189128009ba900337566040603e0024646464a66604066e1d2002002132533302100110011330224913e617574686f72697479546f6b656e7356616c6964496e3a2047415420546f6b656e4e616d6520646f65736e2774206d617463682053637269707448617368000013301b23375e60460026ea4dd718128011bab0041325333021001100113302249137617574686f72697479546f6b656e7356616c6964496e3a2047415420696e636f72726563746c79206c69766573206174205075624b6579000014a0604a00460400026ea8c084c088c08400852898100009bae301d005004149854cc059240120416c6c206f757470757473206f6e6c7920656d69742076616c696420474154730016153301649129506172656e7420746f6b656e20646964206e6f74206d6f766520696e206d696e74696e6720474154730016149854cc0592414d5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f417574686f72697479546f6b656e2e68733a3134343a372d32350016301a00230150013754602c602a004602c602a002602a00244466660080040064666600c0040024002290000a4000446666008466e3cdd7180880080180091118011bab3017003122500122333300323371e6eb8c04000400c004888c008dd6980b00189128009803111299980500089128008a99980698011808800891180118098018998018011808000aba04bd702441002300a300a0012300222533300500114a22a6600c60066018002260046016002464600446600400400246004466004004002aae7c88ccc01000800400c5282b9a5738aae755d12ba1230023754002aae781"},"governorPolicyInfo":{"currencySymbol":"3f57878004c69a4ebcad6907b12e8245e44fd85ebaff8c27dd9c2f4b","policy":"59054d01000032323232323232323232323232323232323222323232533300e3370e90000010991919299980899911919800925114a0664602c44a666032002244a00226660066038002444600400626004603a0024a66602866ebc00cc068c070004488c00800c489400400530127d8799fd8799f581c0b2086cbf8b6900f8cb65e012de4516cb66b5cb08a9aaba12a8b88beff00ff003758602e0062a666022a6601466e1ccc03cdd7180b8021bab3017001480084cdc39991191991199999809919b8f375c603800200600a44460046eacc08800c48940048cccccc0508cdc79bae301d0010030012223002375a6046006244a0024002290000a40006eb8c068004dd7180d180d800980d8009bab301700133223374a9000198059ba90023300b375200297ae0375c602e00891100480084c8c8c8c8c8c8c94cc044c94ccc06400440044cc07524012a45786563757465207468726573686f6c64206973206c657373207468616e206f7220657175616c20746f000013371290000018a9980899299980c800880089980ea481294472616674207468726573686f6c64206973206c657373207468616e206f7220657175616c20746f20000013371290000010a9980899299980c800880089980ea48128566f7465207468726573686f6c64206973206c657373207468616e206f7220657175616c20746f20000013371290000008a9980899299980c800880089980ea4812b4472616674207468726573686f6c64206973206c657373207468616e20766f7465207468726573686f6c640000133712004002264a666032002200226603a9212d45786563757465207468726573686f6c64206973206c657373207468616e20766f7465207468726573686f6c6400001337100020066eb4c074c07800cdd6980e0011bad301b002301b001301b3019301b00133223301049122446174756d206e6f7420666f756e6420696e20746865207472616e73616374696f6e003322333301822533301b0011225001153330183371e646eb8c07cc084004c078004010488c008c08000c4c008c07c004004888c008c07cc080c08400c4894004cc88c8c8c94ccc064cdc3a400000426eb8c07c00454cc07401458c084008c070004dd5000a4920476976656e2054784f757420646f6e657327742068617665206120646174756d000020013018300d301a001375860306460346034601c00260320046601a920119476f7665726e6f72206f7574707574206e6f7420666f756e64003300e23370e660206eb8c060014dd5980c180c980d000a40046eb0c05c00854cc05524012245786163746c79206f6e6520746f6b656e2073686f756c64206265206d696e746564001615330154911f5265666572656e636564207574786f2073686f756c64206265207370656e740016301730170013016001301630143016004153301249014f5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f476f7665726e6f722f536372697074732e68733a3137303a352d34340016301600230110013754602260246026002ae8088ccc02400800400c528118069806800911980090008a998050010b1802911299980480089128008a999803180118060008911801180700189980180118068009119998019ba9002001233300622337006eb4c040008005200037560022900011199980291299980400089128008a99980299baf300a300b0010041223002300d00313002300c0010012223002300f0031225001573444600644a66600c0022006266008601200260046014002464600446600400400246004466004004002aae7d5ce2ab9d5742ae888c008dd5000aab9e01"},"governorValidatorInfo":{"hash":"f975d9a89cf94e58ad4955c9d2a3ce21ce5351909bfc4de4857fc46c","script":"59193901000032323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323222232323232323232323253330563370e90010010991919299982c99b8733049010375660bc60ba0049001099299982d19b873032001480084c94ccc16ccdc3998258091bab3060001480084c94ccc170c8c8c8c8c94cc134c94ccc18800440044cc18d2412a45786563757465207468726573686f6c64206973206c657373207468616e206f7220657175616c20746f000013371290000018a998269929998310008800899831a481294472616674207468726573686f6c64206973206c657373207468616e206f7220657175616c20746f20000013371290000010a998269929998310008800899831a48128566f7465207468726573686f6c64206973206c657373207468616e206f7220657175616c20746f20000013371290000008a998269929998310008800899831a4812b4472616674207468726573686f6c64206973206c657373207468616e20766f7465207468726573686f6c640000133712004002264a6660c400220022660c69212d45786563757465207468726573686f6c64206973206c657373207468616e20766f7465207468726573686f6c6400001337100020066eb4c194c19000cdd698320011bad306300230610013062306130620011323232533305f3370e90010010a99982f99baf0040151533305f3370e6609e08a646660a44466446664446608c6604046466660b4002006466ec0008dd3198031bab30710033756002200460d400200466042460466605e466ebcc1ac004c1ac00800c00488cc114cc07c8c8cccc16400400c8cdd80011ba8337006eb4c1c000cdd680088011834800801198101181119817119baf306a001306a00200300100200137566460d060ce00260d06460d060ce00260d00040020380026eb0c190041200213232533306153304d3025002130250011323232323253330663375e60d600698103d87b8000153330663375e00c66e95200033062306b00533062306b004330623374a90030309983118358011983118358009983118359835000830899299983399b89375a6460da60dc00260d80046eb4c1b80044c8c94ccc1a4cdc39982c8151bab306e018001132533306a3370e608400200426660b844a6660d866e1ccc1700b4dd59838983818390012400020022a6660d866e1ccc1700b4dd5983898381839001240042a660b0002264a660b264a6660dc00220022660de92125474154206d7573742062652074616767656420627920746865206566666563742068617368000013302a02e003132533306e001100113306f49110556e657870656374656420646174756d000013371e660cc921224f757470757420746f206566666563742073686f756c64206861766520646174756d003072307130710013306a4901225265636569766572206973206e6f7420696e2074686520656666656374206c697374003322333305a23371e6eb8c1c800400c004888c008dd7183c8018912800998352491c474154207265636569766572206973206e6f74206120736372697074003232323253330713370e900100109118011bae3078003122500130770023071001375460e660e800260e400200c60e40042941289bac306f01a153306b4901244f75747075742047415473206973206d6f7265207468616e206d696e746564204741547300163306323371090001982d0159bab306f306e3070001375860dc0322a660d4920128526571756972656420616d6f756e74206f6620474154732073686f756c64206265206d696e74656400163040001332232330012001153306b491505061747465726e206d61746368206661696c75726520696e207175616c69666965642027646f2720626c6f636b20617420506c7574617263682f4d617962652f45787472612e68733a31353a352d31310016333305423370e6eb4c1b000400c004888c008dd5983980189128009bad3069001375660d800a2a660d0921314869676765737420766f746520646f65736e2774206d65657420746865206d696e696d756d20726571756972656d656e74001633063491124e6f2077696e6e696e67206f7574636f6d65003330582253330683300124a229404cc00494ccc1a4cdc41bad3070001375a60e0006244600400a20042a660d2921505061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f476f7665726e6f722f536372697074732e68733a3539343a33312d343000161223002004225001375660d660d40022a660ce920120556e6578706563746564206f75747075742070726f706f73616c20646174756d001615330674914850726f706f73616c206d75737420626520696e206c6f636b65642865786563757461626c652920737461746520696e206f7264657220746f20657865637574652065666665637473001630690013068001306700130660013067002153306204416330483065306330663305d4911950726f706f73616c206f7574707574206e6f7420666f756e64003304b23253304e3370e660a40906eacc19cc198005200213375e60ce00208c60ce0026eb0c194040dd61832983200719823983218311832991832983218330009982e2491850726f706f73616c20696e707574206e6f7420666f756e64003304a23253304d3370e660a208e6eacc198c194005200213375e60cc00208a60cc60ca60c860cc0026eb0c190040dd6183218318068a998302493454686520676f7665726e6f722063616e206f6e6c792070726f63657373206f6e652070726f706f73616c20617420612074696d650016153306049124476f7665726e6f722073746174652073686f756c64206e6f74206265206368616e67656400161533305f3370e90020010a998259929998300008800899830a493373696e676c65417574686f72697479546f6b656e4275726e65643a204d757374206275726e2065786163746c79203120474154000013370e6609e0406eacc190038cdc0a4000900109929998300008800899830a494673696e676c65417574686f72697479546f6b656e4275726e65643a20416c6c2047415420746f6b656e73206d7573742062652076616c69642061742074686520696e70757473000013301e23301d02132306630650013066001375860c860ca60c80242a6660be66ebc010cdd2a4000660b660c800e660b66ea0c8cdc0000a40046eb4c190c18c01c16854ccc17cc94cc130cdc399828023000a4004266e1cc0e00052002375660c801c26464a6660c2604860cc60ca00226464a6660c666e1cdd69834001181e1bab30680031533306333223306322533306600114a02a6660ce66ebcc1b000400c5288980118358008011bac3068011306800113253330643370e607800290010992999832981400089929998331815000899191919299983519baf306f004306f306e0121533306a3375e60de00260de0242a6660d466ebcc1bc00d30103d87980001533306a3370e60846eb0c1bc00920021533306a3375e6ea4dd7183780418379bac306f00213232533306c3370e6eb4c1c402cc114dd598388008a99983619baf3374a9000198341838805998341838805198341ba73304b375860e260e00146609a64466e9520003306a0013306a37500040d26eb4c1c4018c130dd598389838001833998348271983119832a491e5374616b65206f75747075742073686f756c64206861766520646174756d0030713070001375860e260e00342930a99836a4811d556e6578706563746564207374616b65206f757470757420646174756d0016153306d491315374616b6564204754732073686f756c642062652073656e74206261636b20746f207374616b652076616c696461746f720016306f30710013306704c330552325330583375e60e20020b4266e1ccc17017cdd598389838000a400460e20026eb0c1bc06854cc1ad240122436f7369676e65722073686f756c6420626520746865207374616b65206f776e65720016153306b4912650726f706f73616c2073686f756c642068617665206f6e6c79206f6e6520636f7369676e65720016153306b4911e50726f706f73616c2073746174652073686f756c642062652064726166740016153306b49124496e76616c6964207468726573686f6c647320696e2070726f706f73616c20646174756d0016153306b49125496e76616c69642070726f706f73616c20696420696e2070726f706f73616c20646174756d0016306d001306c001306b306b001306c0011533067049163304d001375860d460d20262a660cc920137546865207574786f207061696420746f207468652070726f706f73616c2076616c696461746f72206d757374206861766520646174756d001632306a3068306b001306900115330654915345786163746c79206f6e65205554584f20776974682070726f706f73616c20737461746520746f6b656e2073686f756c642062652073656e7420746f207468652070726f706f73616c2076616c696461746f7200163305d2325330513375e60d4002092266e1ccc15412cdd598351834800a400460d40026eb0c1a004c54cc1912412654782073686f756c64206265207369676e656420627920746865207374616b65206f776e65720016153306449130526571756972656420616d6f756e74206f66207374616b65204754732073686f756c642062652070726573656e7465640016306600130673304930663065001375860cc60ca01e2a660c49211e5374616b6520696e70757420646f65736e2774206861766520646174756d0016306430663065306430660013305c4901155374616b6520696e707574206e6f7420666f756e64003304a23253304d3375e60cc00209e266e1ccc144150dd598331832800a400460cc60ca60c860cc0026eb0c19004054cc1812412945786163746c79206f6e652070726f706f73616c20746f6b656e206d757374206265206d696e746564001615330604911f556e657870656374656420676f7665726e6f7220737461746520646174756d00163065002305f00137546464646402aa6660be66e1d20000021324994ccc1780045261533060054161533305f3370e900100109924ca6660bc0022930a9983002a0b0a99982f99b87480100084c926533305e001149854cc1801505854cc1812413f7265616368656420656e64206f662073756d207768696c65207374696c6c206e6f7420686176696e6720666f756e642074686520636f6e7374727563746f7200163065002305f00137540222a660ba9201164e657720646174756d206973206e6f742076616c6964001633058491244f7570757420676f7665726e6f7220737461746520646174756d206e6f7420666f756e64003305133054490122476f7665726e6f72206f757470757420646f65736e2774206861766520646174756d003060305f001375860c060be0122a660b89212d537461746520746f6b656e2073686f756c64207374617920617420676f7665726e6f72277320616464726573730016305e3060305f001153305b49012f45786163746c79206f6e65207574786f2073686f756c642062652073656e7420746f2074686520676f7665726e6f72001633223305523375e60c260c40020040046eb0c178024c17800854cc1692412d4f776e20696e7075742073686f756c6420686176652065786163746c79206f6e6520737461746520746f6b656e0016305e00e305d305c305b305d00133053491134f776e20696e707574206e6f7420666f756e64003322332305722533305a001122500113330033060001222300200313002305f001253330593375e00660bc60be0022446004006244a00200260b60026eb0c16c01c54cc15d24014f5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f476f7665726e6f722f536372697074732e68733a3239323a352d35390016305c0023056001375460b060ae00c6460ae60ac00260ac00260aa60aa00260a800260aa00260a600260a60020029111c3f57878004c69a4ebcad6907b12e8245e44fd85ebaff8c27dd9c2f4b002304622533304900110061330463003304f0013002304e001230452253330480011005132533304a30040011330460013003304e00213003304e002304e00123330460014a09452f5bded8c04464666606e6ea400cdd5982598250009191919299982519b87480080084c94ccc12c00440044cc130024004cc0248cdd798268009ba9375c60a00046eac0104c94ccc12c00440044cc13002c00528182800118250009baa304c304d304c00214a2609600292013e617574686f72697479546f6b656e7356616c6964496e3a2047415420546f6b656e4e616d6520646f65736e2774206d617463682053637269707448617368002304022533304300114a22a660606006609200226004609000292137617574686f72697479546f6b656e7356616c6964496e3a2047415420696e636f72726563746c79206c69766573206174205075624b6579000014891c6aa44a4ea34725d9bcf9b522babe6b6b94ae55eddac23b9ccaa9442700232323253330413370e90010010a5014a2608e00460820026ea80040048c8c94cc0a8c94ccc0fc00440044cc100014004cc014020dd598218010a9981519299981f800880089982000500098051bac3043001153302a32533303f001100113304000c00133712602c6eb0c10c005200a132533303f001100113304000d0013300d375660860046eacc10cc108c108004c104c104004c100c10800524013250726f706f73616c20686173206174206c65617374206f6e6520526573756c7454616720686173206e6f2065666665637473002303822533303b00114a02a660086006608200226004608000246607200200429448c034dd5981f000a4812250726f706f73616c20686173206174206c65617374206f6e6520636f7369676e6572002533303400114a029452412b50726f706f73616c2068617320666577657220636f7369676e657273207468616e20746865206c696d69740049013950726f706f73616c20766f74657320616e6420656666656374732061726520636f6d70617469626c6520776974682065616368206f746865720022323253330353370e601a004601a00226600a6600c0180046600c0180022940c050008c04c008c0b88894ccc0c800854ccc0c80045288a501533303200114a02a66606666ebcc0e0008c0e00044cc00cc0dc008c0dc00452818169112999819180400088168a9998191804181b00088008998020009119980480219802802001198028020009198010008009815911299981818030008919800816001899191929998199804801891980098040018010991998038010009111980099819803001801181b801981b002181b001981a000919814800814181491112999817980280108008a99981798028008801099191919299981999803802001099817802199804003801802899817801199804003803000981b002181b001981a001981a0012ba322337106eb4008dd6800998131112999815000880109980199b8000248008c0bc005200000123232333004003375c605c0026eb8c0b8c0b4004c0b8004cdd2a4000660466ea4014cc08cdd480281111119998020010019199980300100090008a400029000111999808919b8f375c605200200600244460046eacc0c000c489400488cccc0408cdc79bae30280010030012223002375a605e006244a00291010022330212253330240011003133021302a001300230290010022330020230012301e225333021001101d13301e3003302700130023026001491165374616b65206f7574707574206e6f7420666f756e640049011c50726f706f73616c20646174756d206d7573742062652076616c6964000014c129d8799fd87a9f581c44fd51f02679fe98ba45c64eea4b7169cad2f573439e542ef08cff3dffd87a80ff000014891c8fd3f732c764550a66a42f31e5936b6dc9f85eabb5c08c774cebd3cd002233017003330123301300400200149122446174756d206e6f7420666f756e6420696e20746865207472616e73616374696f6e00490120476976656e2054784f757420646f6e657327742068617665206120646174756d00301322253330170011225001153330183002301d0011223002301f003133003002301c0012233301600200100314a000298129d8799fd87a9f581c9aecaa97f19230ddfcd5c67fdab9a032783ed2aba422362b68a63253ffd87a80ff002233330033752004002466600a4466e00dd6980e001000a40006eac0045200022333300f2253330120011225001153330133375e602a60300020082446004603400626004602e00200244460046036006244a00244601c44a6660220022006266008602e0026004602c0020029111c55d252e7c81d25e68ed198a26f07832f838c4d1f078e7d28bd18c209004901186c697374206973206c6f6e676572207468616e207a65726f002233330030020012223002003122500100122333300822533300b00112250011533300c3371e646eb8c048c04c004c044004010488c008c04c00c4c008c040004004888c008c048c044c04c00c489400488c8c8c94ccc030cdc3a400000426eb8c04400454cc03401458c048008c030004dd500091802912999804000880209929998051802000899803000980198070010980198070011807000a5eb815d0111980090008a998030010b119180111980100100091801119801001000aab9f5734ae7155ce918011801000aba25742460046ea800555cf01"},"proposalPolicyInfo":{"currencySymbol":"8fd3f732c764550a66a42f31e5936b6dc9f85eabb5c08c774cebd3cd","policy":"5902d501000032323232323232323232323232323232223232323232533300e3370e90000010991919299980899b874800000854ccc044cc88cdc42400066644602644a66602c0022006266008603c0026004603a0024466e00004cc88c8ccc04800cdd7180f8009bae301f301e001301f001375660386036603a64603a6038002603a0040089000000999119ba548000cc050dd48011980a1ba90010154891c3f57878004c69a4ebcad6907b12e8245e44fd85ebaff8c27dd9c2f4b000143758603000e2a66602266e1ccc88c8ccc03800cdd7180d8009bae301b301a001301b001375660306460306030002602e00e664466e952000330143752004660286ea4004054dd7180c00080a240042930a9980aa4811e4d696e7465642065786163746c79206f6e652070726f706f73616c2053540016153301549127476f7665726e616e63652073746174652d74687265616420746f6b656e206d757374206d6f7665001615330154914e5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f50726f706f73616c2f536372697074732e68733a37373a352d32330016301900230140013754602a602800a2a6602492014e5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f50726f706f73616c2f536372697074732e68733a37323a352d323300163016002301100137546024602200460246022002602200244466660080040064666600c0040024002290000a4000446666008466e3cdd7180680080180091118011bab3013003122500122333300323371e6eb8c03000400c004888c008dd6980900189128009800911299980280089128008a99980318011806800891180118078018998018011806000919180111980100100091801119801001000aab9f5734ae812f5c0911005738aae755d12ba1230023754002aae781"},"proposalValidatorInfo":{"hash":"44fd51f02679fe98ba45c64eea4b7169cad2f573439e542ef08cff3d","script":"5909bf010000323232323232323232323232323232323232323232323232323232323232323232323232222323232323232323253330253370e9001001099999119999181291299981400089128008999801981900091118010018980118188009299981419baf003303030310011223002003122500100122230023032303130330031225001302d0013758605a00c4646464646464646464646464a66606466e1c0112002132323253330353370e9001001099299981b199119b873021001302153330383020001100113233330362222533303d30250011302400213232533303f3300500200413330060050040011330390043330060050020013045002304500175e6082002608000266606a444a6660766046002205e2a66607660466084002200226666070444a66607c604c00224660020660062646464a66608260520062466002605200600426466600e004002444660026607e00c0060046090006608e008608e006608a0020020024466660744444a666082605200420022a66608260520022004264646464a66608a6600e00800426607e00866601000e00600a26607e00466601000e00c00260960086096006609200660920040086600a0080046600a0080020040024466e40dd70011bae0010011533303633020005001153330363370e00c603e0022a66606c66040466666444666605a46464646464a66608066e1d200200214a02a66608066e1c01120021333302b375c6090002010466ebcc124c120c128004dd48050a5014a0609200460840026ea8c114c110008cc88c8ccc0bc00cdd718238009bae3047304600130470013756608800201a60846088646088608600260880020024646464a66607c66e1d2000002133029375c608c00200c244a002608e00460800026ea8c10cc104c110c10cc108c1100044894004dd70009bac303f303e0163758607e03049445280008a99981b1991191981a91919191919299981f99b874800800854cc1092401455061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5574696c732e68733a3533393a31352d323300161333302a375c608e0026eb0c11cc8c11cc11cc11cc114004c11801c8ccc024dd5982400298240030008a5030480023041001375460886086002608400260860026eb0c104004c0fcc104008c0f80648894cc09cc94ccc0e800440044cc0f524115446174756d206d75737420626520636f7272656374000013375e00266e95200033033304101233033304101133033304101033033374e6605e0086eb0c10403ccc0ccc104038cc0ccc104c1000380b454cc09cc94ccc0e800440044cc0f524011756616c75652073686f756c6420626520636f7272656374000013375e6e98dd5982098200099ba6003132533303a001100113303d4901224d7573742062652073656e7420746f2050726f706f73616c27732061646472657373000013375e01a0042930a9981ca481325369676e6174757265732061726520636f72726563746c7920616464656420746f20636f7369676e6174757265206c6973740016153303949135416c6c206e657720636f7369676e65727320617265207769746e6573736564206279207468656972205374616b6520646174756d7300161533039491254173206d616e79206e657720636f7369676e657273206173205374616b6520646174756d73001615330394911b5369676e656420627920616c6c206e657720636f7369676e6572730016153303949114436f7369676e6572732061726520756e6971756500163758607a002293181f001181b8009baa0171533035490116535420617420696e70757473206d757374206265203100163223303022533303300114a02a66606a66ebcc0f400400c52889801181e0008011bac303901032333021004375c60720026eb8c0e4c0e0004c0e4004cc88cdd2a4000660566ea4008cc0acdd4800812a451c55d252e7c81d25e68ed198a26f07832f838c4d1f078e7d28bd18c2090048811c9aecaa97f19230ddfcd5c67fdab9a032783ed2aba422362b68a6325300332233330283752004002466604c4466e00dd6981e801000a40006eac004520004891c8fd3f732c764550a66a42f31e5936b6dc9f85eabb5c08c774cebd3cd00001323330232233223332223302b3302c232333302f0010032337600046e98cc018dd598210019bab0011002303a0010023302e230313303223375e60760026076004006002446605466056464666605c002006466ec0008dd419b80375a60820066eb40044008c0e4004008cc0b48c0c0cc0c48cdd7981d000981d0010018008010009bab32303930380013039323039303800130390020010300013758606a01c606800c606400260620026060002605e002606001a605e0022a660509214f5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f50726f706f73616c2f536372697074732e68733a3132393a352d3135001615330284914f5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f50726f706f73616c2f536372697074732e68733a3132373a352d34340016302e002302700137546054605200a604c6050002604c604e0026050002604c002604c00246602800201cae8ccc0508894ccc06000440084cc00ccdc000124004604200290001180a11299980b8008a51153300730033021001130023020001223333003002001222300200312250010012233330122253330150011225001153330173371e646eb8c080c084004c07c004010488c008c08400c4c008c078004004888c008c080c07cc08400c489400488ccc05000800400c52811119998020010019199980300100090008a400029000111999802119b8f375c602c00200600244460046eacc07800c489400488cccc00c8cdc79bae30150010030012223002375a603a006244a0026014444a66601c002244a0022a6660206004603000224460046034006266006004602e00297ae022300a22533300d0011003133004301700130023016001223300922533300c00110031330083016001300230150010022300722533300a001100e133006300330140013002301300122333300722533300a00112250011533300c3375e602060280020082446004602c0062600460260020024446004602e006244a0024600a44a6660100022018264a666016600800226600a002600660240042600660240046024002ae808ccc018005282512300222533300500114a02a6600c6006601e00226004601c002464600446600400400246004466004004002aae7c8cc00800400d5cd0a514bd6f7b6302b9c5573a460066004002460046004002ae895d0918011baa0015573c1"},"stakePolicyInfo":{"currencySymbol":"55d252e7c81d25e68ed198a26f07832f838c4d1f078e7d28bd18c209","policy":"5906fa0100003232323232323232323232323232323232323232323232323232323232323232323232323232323232323232223232323232323232533302e3370e90000010991919299981899b884800000454ccc0c4cdc3801240002a66606266e1c00520021533303132323302f2323232323253330393370e90010010a9981e2481455061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5574696c732e68733a3533393a31352d3233001613333020375c607e0026eb0c0fcc08cc0f801c8ccc024dd5982000298200030008a503040002303b001375460786076002607400260760026eb0c0e4004c0dcc0e402c888c8c8c94ccc0dccdc3a400000429404c8c94cc09ccc88cc0e0894ccc0ec0045280a99981e99baf304300100314a22600460840020046eb0c0fcc098c0f803cc0fcc0f800854cc09ccc058020cc0b0c070dd6981f80119980f005800a40042a6604e6602c0106605860386eb4c0fc008ccc07802c0052002132337126660320020180046660320120180046605860386eb4c0fc008ccc07802c0052002375c607c004607c008607c00460720026ea8c0e8c0ec008526153303449012941205554584f206d75737420657869737420776974682074686520636f7272656374206f7574707574001615330344911b4d696e746564205354206d7573742062652065786163746c7920310016153303449116535420617420696e70757473206d75737420626520300016153330313370e00490010a99981899b87001337029000240042a66606264646605e46464646464a66607266e1d200000213333020375c607e0026eb0c0fcc8c0fcc090004c0f801c8ccc024dd5982000298200030008a50153303c4901455061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5574696c732e68733a3538393a31352d323300163040002303b00137546078607600260740026076646076607400260760026eb0c0e4004c0e402c8894cc088cdc399812803001a40042605e64a66606600229405289bac303a3024303b001149854cc0d12412a416e20756e6c6f636b656420696e707574206578697374656420636f6e7461696e696e6720616e20535400161533034491095354206275726e65640016153303449116535420617420696e70757473206d75737420626520310016330210023756606c00c6604000264666044446604a6eacc8c0e4c0e0004c0e4c8c0e4c0e0004c0e40080040c8004dd6181a8039bae3034001153303149014b5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5374616b652f536372697074732e68733a38313a352d323300163035002303000137546062606000a605e605e002605c002605e002605a002605a0024466e24c00c004c00c0088ccc00800401c01c888cccc01000800c8cccc01800800480045200014800088cccc0108cdc79bae302700100300122230023756605a006244a002446666006466e3cdd7181300080180091118011bad302c0031225001301b222533301f001122500115333021300230270011223002302900313300300230260012333003002002001489002223004337606ea400cdd3180219bb037520046ea00048cc05400407488cccc00c008004888c00800c489400400488cccc058894ccc064004489400454ccc06ccdc7991bae30223023001302100100412230023023003130023020001001222300230223021302300312250012301c30020012301b30020012301a30020012301930040012233301400200100314a04602c602c0024466660126ea40080048ccc01088cdc01bad301c00200148000dd58008a400044601a44a666020002200626600860300026004602e002446660064466600ce00008004008004888cc014cc0188c8cccc02400400c8cdd80011ba633006375660340066eac0044008c050004008cc0208c02ccc0308cdd7980a800980a80100180091119802198029191999804000801919bb000237506600c6eb4c06400cdd680088011809800801198039180519805919baf30140013014002003001223300922533300c00110031330083014001300230130010022300722533300a001100e133006300330120013002301100122333300722533300a00112250011533300c3375e60206024002008244600460280062600460220020024446004602a006244a0024600a44a6660100022018264a666016600800226600a002600660200042600660200046020002ae808ccc018005282512300222533300500114a02a6600c6006601a002260046018002464600446600400400246004466004004002aae7c8cc00800400d5cd0a514bd6f7b6302b9c5573aae895d0918011baa0015573c1"},"stakeValidatorInfo":{"hash":"9aecaa97f19230ddfcd5c67fdab9a032783ed2aba422362b68a63253","script":"590b7101000032323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232222323232323232323232533303e3370e90010010999991199181f91299982100089128008999801982480091118010018980118240009299982099baf003304730480011223002003122500100130440013758608800e464646464646464646464a66609266e1d2000002153330493370e00c90010a999824981f0020a9998248048a9998249980f009911191929981599299982780088008998292490f697353637269707441646472657373000013375e00801e2a6605664a66609e00220022660a405e002a6605666ebcc150c14c050c150c14c00854cc0accdc399b80375a60a80280026eb4c1500084cdc4a40006eb4c1500084c94ccc13c00440044cc1480b80054cc0accc074014cc0f0c8dd5982a982a182b000982a1829982a808180f8008a998159980e8029981e191bab305530543056001305430533055010301f00113233712660920980026609209800c66078646eacc154c150c158004c150c14cc154040c07c004dd6982980298298008a4c2a660980542c2a660980562c2a660980582c2a6609805a2c2a66609266e1d200400215333049009153330493370e00a90010a9998249980f009911299982619baf00200d132533304d001100113305002c0013375e6e98c8dd598299829182a0009829182898298071ba600314a02930a998260150b0a9982600e8b0a998260158b0a99982499b874801800854ccc12402454ccc124cdc3803240042a66609266e1c0152002153330493301e013222533304c3375e00401a264a66609a00220022660a005800266ebcdd3191bab30533052305400130523051305300e374c0062940526153304c02a16153304c01d16153304c02d16153304c02b16153330493370e90040010a99982499b870064800854ccc1254cc1000244cc88cdc42400066608e4466e00004cc88c8ccc0dc00cdd7182b0009bae305630550013056001375660a660a460a86460a860a600260a8004008900000099ba548000cc0f4dd481a9981e9ba90360343758609e0242a6660926603c026444a66609866ebc00803454cc0a4c94ccc13400440044cc1400b0004cdd79ba632375660a660a460a800260a460a260a601c6e9800c4c94ccc13400440044cc1400b4004cdd780080d0a50149854cc1300a85854cc1312401374f776e6572207369676e732074686973207472616e73616374696f6e204f522070726f706f73616c20746f6b656e206973207370656e740016153304c02d16153330493370e00c90010a99982499b87008337029000240042a666092607c0082a6660920122930a998260158b0a998260160b0a9982624810e53686f756c64206275726e2053540016153304c02d163050002304b00137546464646402ea66609266e1d20000021323232324994ccc12c004526153304f031163050003375a002609e0022a66609266e1d20020021324994ccc120004526153304c02e16153330493370e9002001099191924ca6660940022930a998270180b182780118278008a99982499b87480180084c8c8c8c926533304b001149854cc13c0c458c14000ccc8c124894ccc13000440e04cc104c00cc14c004c008c1480048c8c8c8c80154ccc138cdc3a40000042646464646464649329998298008a4c2a660ae0722c60b00066eb4004c15c004c15400cdd6800982a0008a9982881a0b182a80118280009baa0013758002609e0022a66609266e1d20080021324994ccc120004526153304c02e16153304c02f163050002304b001375402664a66608a00229405289bac304b3047304c013323233302d004375c60980026eb8c130c12c004c130004cdd2a4000660706ea40c0cc0e0dd48188179981e8200009919981f91198199bab32304c304b001304c32304c304b001304c00200103c001375860900166607607c6eacc11c020cc88cc100894ccc10c0045280a99982219baf304a00100314a22600460920020046eb0c118c104c11401cc118c114018c8c118c11c004c114c110c11800454cc10524014c5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5374616b652f536372697074732e68733a3232393a352d3138001615330414914c5061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5374616b652f536372697074732e68733a3232373a352d323200163045002304000137546082608000c6082010607c607c002607a002607c002607800260780024466e24c00c004c00c0088ccc0600040780788ccc008074074004888c010cdd81ba9003374c600866ec0dd48011ba800123302200102749011150726f706f73616c205354207370656e74002232330242323232323253330343370e90010010a9981b8050b099998059bae303a00137586074601c607200e46660126eacc0ec014c0ec018004528181d801181b0009baa30373036001303500130360013758606800260646068004921455061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f5574696c732e68733a3533393a31352d3233002233330030020012223002003122500100122333302722533302a00112250011533302b3371e646eb8c0c8c0cc004c0c4004010488c008c0cc00c4c008c0c0004004888c008c0c8c0c4c0cc00c48940048c0b0c0080048c0acc0080048c0a8c09800488ccc09400800400c5282490c76616c7565436f727265637400490112636f72726563744f7574707574446174756d0049012941205554584f206d75737420657869737420776974682074686520636f7272656374206f75747075740049011c4f776e6572207369676e732074686973207472616e73616374696f6e0049010e5374616b6520756e6c6f636b656400490116535420617420696e70757473206d7573742062652031004901186c697374206973206c6f6e676572207468616e207a65726f0049013f7265616368656420656e64206f662073756d207768696c65207374696c6c206e6f7420686176696e6720666f756e642074686520636f6e7374727563746f720022233330040020032333300600200120011480005200022333300423371e6eb8c07c00400c004888c008dd598128018912800911999801919b8f375c603c00200600244460046eb4c09000c4894004c0508894ccc060004489400454ccc064c008c07c004488c008c08400c4cc00c008c0780052f5c091011c8fd3f732c764550a66a42f31e5936b6dc9f85eabb5c08c774cebd3cd0048810022333003223330067000040020040024446600a6600c4646666022002006466ec0008dd3198031bab301f0033756002200460320020046600e4601466016466ebcc068004c06800800c004888cc010cc0148c8cccc04000400c8cdd80011ba833006375a603c0066eb40044008c060004008cc0188c024cc0288cdd7980c800980c80100180091198079129998090008801899803980c8009801180c0008011180691299980800088050998029801980b8009801180b000918061129998078008804899299980898020008998028009801980b00109801980b001180b000aba0233300c0014a09448c024894ccc0300045280a99802180198098008980118090009198050008010a514bd6f7b6301119998019ba9002001233300522337006eb4c04c008005200037560022900011199980291299980400089128008a99980499baf300d300f0010041223002301100313002300e0010012223002301200312250012230042253330070011003133004300e0013002300d00148811c55d252e7c81d25e68ed198a26f07832f838c4d1f078e7d28bd18c209002323002233002002001230022330020020015573eae688c014c0080048c010c0100055ce2ab9d5744ae848c008dd5000aab9e1"},"treasuryValidatorInfo":{"hash":"39ad85486d8624a49f080636324f80938febfb91552709c70a3ac00e","script":"590338010000323232323232323232323232323222232323232533300e3370e90000010992999807a99806992999808000880089980924813373696e676c65417574686f72697479546f6b656e4275726e65643a204d757374206275726e2065786163746c79203120474154000013370e6466660146ea40440048ccc88c03c894ccc048004400c4cc010c064004c008c06800488cdc01bad301a00200148000dd58008a40006eacc04cc8c054c054c054004c054004cdc0a400090010992999808000880089980924814673696e676c65417574686f72697479546f6b656e4275726e65643a20416c6c2047415420746f6b656e73206d7573742062652076616c69642061742074686520696e70757473000013300a23232333300c37520266eacc058c05c0048c8c8c94ccc058cdc3a4004004264a66602e00220022660329213e617574686f72697479546f6b656e7356616c6964496e3a2047415420546f6b656e4e616d6520646f65736e2774206d617463682053637269707448617368000013301123375e60340026ea4dd7180d8011bab0041325333017001100113301949137617574686f72697479546f6b656e7356616c6964496e3a2047415420696e636f72726563746c79206c69766573206174205075624b6579000014a06038004602e0026ea8c05cc064c05c008528980b80099180a980b000980b0009bac30133015001149854cc04524128412073696e676c6520617574686f7269747920746f6b656e20686173206265656e206275726e65640016301200415330104901465061747465726e206d61746368206661696c75726520696e2027646f2720626c6f636b2061742061676f72612f41676f72612f54726561737572792e68733a38353a332d313200163014002300f0013754601e6020002602000244666600844a66600e002244a0022a66601466ebcc034c038004010488c008c04000c4c008c03c004004888c008c04800c48940048c008894ccc0140045288a9980318019806000898011806800919180111980100100091801119801001000aab9f2233300400200100314a0ae692211c6aa44a4ea34725d9bcf9b522babe6b6b94ae55eddac23b9ccaa94427005738aae755d0aba2230023754002aae781"}} \ No newline at end of file diff --git a/agora.cabal b/agora.cabal index be3d748..3d83793 100644 --- a/agora.cabal +++ b/agora.cabal @@ -145,11 +145,10 @@ library Agora.Treasury Agora.Utils Agora.Utils.Value - Agora.ScriptInfo - Agora.Aeson.Orphans other-modules: + Agora.Aeson.Orphans hs-source-dirs: agora library pprelude diff --git a/agora/Agora/ScriptInfo.hs b/agora/Agora/ScriptInfo.hs index 54a709e..f9643ae 100644 --- a/agora/Agora/ScriptInfo.hs +++ b/agora/Agora/ScriptInfo.hs @@ -25,7 +25,9 @@ import Plutus.V1.Ledger.Value (CurrencySymbol) -- | Bundle containing a 'Validator' and its hash. data ValidatorInfo = ValidatorInfo { script :: Validator + -- ^ The validator script. , hash :: ValidatorHash + -- ^ Hash of the validator. } deriving stock (Show, Eq, GHC.Generic) deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) @@ -43,7 +45,9 @@ mkValidatorInfo term = -- | Bundle containing a 'MintingPolicy' and its symbol. data PolicyInfo = PolicyInfo { policy :: MintingPolicy + -- ^ The minting policy. , currencySymbol :: CurrencySymbol + -- ^ The symbol given by the minting policy. } deriving stock (Show, Eq, GHC.Generic) deriving anyclass (Aeson.ToJSON, Aeson.FromJSON) diff --git a/agora/Agora/Treasury.hs b/agora/Agora/Treasury.hs index f472243..475c936 100644 --- a/agora/Agora/Treasury.hs +++ b/agora/Agora/Treasury.hs @@ -72,6 +72,7 @@ deriving via do so in a valid manner. -} treasuryValidator :: + -- | Governance Authority Token that can unlock this validator. CurrencySymbol -> ClosedTerm PValidator treasuryValidator gatCs' = plam $ \_datum redeemer ctx' -> unTermCont $ do From fce27a2e3c57fd1ea48f82f9fde11d2080181149 Mon Sep 17 00:00:00 2001 From: fanghr Date: Tue, 24 May 2022 01:27:04 +0800 Subject: [PATCH 25/25] fix a typo --- agora/Agora/Effect/GovernorMutation.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agora/Agora/Effect/GovernorMutation.hs b/agora/Agora/Effect/GovernorMutation.hs index 4b929f2..fb28e33 100644 --- a/agora/Agora/Effect/GovernorMutation.hs +++ b/agora/Agora/Effect/GovernorMutation.hs @@ -116,7 +116,7 @@ instance PTryFrom PData (PAsData PMutateGovernorDatum) where {- | Validator for the governor mutation effect. This effect is implemented using the 'Agora.Effect.makeEffect' wrapper, - meaning that the burning of GAT is checked in the said wrapper. + meaning that the burning of GAT is checked in said wrapper. In order to locate the governor, the validator is parametrized with a 'Agora.Governor.Governor'.