create initial POC script generating API
This commit is contained in:
parent
564b1c4e66
commit
e862de7e59
9 changed files with 210 additions and 82 deletions
|
|
@ -1,68 +1,49 @@
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{- |
|
|
||||||
Module : API
|
|
||||||
Maintainer : emi@haskell.fyi
|
|
||||||
Description: API for script exporter.
|
|
||||||
|
|
||||||
API for script exporter.
|
{- | Module : API
|
||||||
|
Maintainer : emi@haskell.fyi
|
||||||
|
Description: API for script exporter.
|
||||||
|
|
||||||
|
API for script exporter.
|
||||||
-}
|
-}
|
||||||
|
module API (
|
||||||
|
AgoraScripts (..),
|
||||||
|
ScriptParams (..),
|
||||||
|
API,
|
||||||
|
agoraScripts,
|
||||||
|
runServer,
|
||||||
|
) where
|
||||||
|
|
||||||
module API (AgoraScripts(..), ScriptParams(..), API, agoraScripts, runServer) where
|
import Agora.AuthorityToken (AuthorityToken (..), authorityTokenPolicy)
|
||||||
|
import Agora.Governor (Governor (..))
|
||||||
import Servant.API (type (:>), ReqBody, JSON, Post)
|
import Agora.Governor qualified as Governor
|
||||||
import PlutusLedgerApi.V1 (TxOutRef)
|
import Agora.Governor.Scripts (authorityTokenFromGovernor, authorityTokenSymbolFromGovernor, governorPolicy, governorValidator, proposalFromGovernor, stakeFromGovernor)
|
||||||
import Data.Tagged (Tagged)
|
import Agora.Proposal (Proposal (..))
|
||||||
import Agora.SafeMoney (GTTag)
|
import Agora.Proposal.Scripts (proposalPolicy, proposalValidator)
|
||||||
import PlutusLedgerApi.V1.Value (AssetClass, CurrencySymbol)
|
import Agora.ScriptInfo (mkPolicyInfo, mkValidatorInfo)
|
||||||
import qualified Data.Aeson as Aeson
|
import Agora.Stake (Stake (..))
|
||||||
import qualified GHC.Generics as GHC
|
import Agora.Stake.Scripts (stakePolicy, stakeValidator)
|
||||||
import Agora.ScriptInfo (PolicyInfo, ValidatorInfo, mkPolicyInfo, mkValidatorInfo)
|
|
||||||
import Agora.Stake (Stake(..))
|
|
||||||
import Agora.Proposal (Proposal(..))
|
|
||||||
import Agora.AuthorityToken (AuthorityToken(..), authorityTokenPolicy)
|
|
||||||
import Agora.Governor (Governor(..))
|
|
||||||
import Development.GitRev (gitBranch, gitHash)
|
|
||||||
import qualified Agora.Governor as Governor
|
|
||||||
import qualified PlutusLedgerApi.V1.Value as Value
|
|
||||||
import Plutarch.Api.V1 (mintingPolicySymbol, mkMintingPolicy)
|
|
||||||
import Agora.Governor.Scripts (governorPolicy, authorityTokenSymbolFromGovernor, authorityTokenFromGovernor, proposalFromGovernor, stakeFromGovernor, governorValidator)
|
|
||||||
import Agora.Treasury (treasuryValidator)
|
import Agora.Treasury (treasuryValidator)
|
||||||
import Agora.Proposal.Scripts (proposalValidator, proposalPolicy)
|
import Codec.Serialise.Orphans ()
|
||||||
import Agora.Stake.Scripts (stakeValidator, stakePolicy)
|
import Data.Cache.Cached (cachedFor)
|
||||||
import qualified Servant.Server as Servant
|
|
||||||
import Data.Proxy (Proxy(Proxy))
|
|
||||||
import qualified Network.Wai.Handler.Warp as Warp
|
|
||||||
import Data.Function ((&))
|
import Data.Function ((&))
|
||||||
import qualified Network.Wai as Wai
|
import Data.Proxy (Proxy (Proxy))
|
||||||
import qualified Network.HTTP.Types as Http
|
import Development.GitRev (gitBranch, gitHash)
|
||||||
import Prettyprinter (layoutPretty, defaultLayoutOptions, hsep, viaShow, (<+>))
|
import Network.HTTP.Types qualified as Http
|
||||||
|
import Network.Wai qualified as Wai
|
||||||
|
import Network.Wai.Handler.Warp qualified as Warp
|
||||||
|
import Network.Wai.Middleware.Cors (CorsResourcePolicy (corsRequestHeaders), cors, simpleCorsResourcePolicy)
|
||||||
|
import Options (Options (..))
|
||||||
|
import Plutarch.Api.V1 (mintingPolicySymbol, mkMintingPolicy)
|
||||||
|
import PlutusLedgerApi.V1.Value (AssetClass, CurrencySymbol)
|
||||||
|
import PlutusLedgerApi.V1.Value qualified as Value
|
||||||
|
import Prettyprinter (defaultLayoutOptions, hsep, layoutPretty, viaShow, (<+>))
|
||||||
import Prettyprinter.Render.String (renderString)
|
import Prettyprinter.Render.String (renderString)
|
||||||
import Options (Options(..))
|
import Servant.API (JSON, Post, ReqBody, type (:>))
|
||||||
|
import Servant.Server qualified as Servant
|
||||||
|
import System.Clock (TimeSpec (TimeSpec))
|
||||||
import Text.Printf (printf)
|
import Text.Printf (printf)
|
||||||
|
import Types (AgoraScripts (..), ScriptParams (..))
|
||||||
-- | Params required for creating script export.
|
|
||||||
data ScriptParams = ScriptParams
|
|
||||||
{ governorInitialSpend :: TxOutRef
|
|
||||||
, gtClassRef :: Tagged GTTag AssetClass
|
|
||||||
, maximumCosigners :: Integer
|
|
||||||
}
|
|
||||||
deriving anyclass (Aeson.ToJSON, Aeson.FromJSON)
|
|
||||||
deriving stock (Show, Eq, GHC.Generic)
|
|
||||||
|
|
||||||
-- | Scripts that get exported.
|
|
||||||
data AgoraScripts = AgoraScripts
|
|
||||||
{ gitRev :: String
|
|
||||||
, 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)
|
|
||||||
|
|
||||||
-- | Servant API type for script generation.
|
-- | Servant API type for script generation.
|
||||||
type API = "generate-scripts" :> ReqBody '[JSON] ScriptParams :> Post '[JSON] AgoraScripts
|
type API = "generate-scripts" :> ReqBody '[JSON] ScriptParams :> Post '[JSON] AgoraScripts
|
||||||
|
|
@ -84,8 +65,20 @@ runServer options = do
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
corsPolicy =
|
||||||
|
simpleCorsResourcePolicy
|
||||||
|
{ -- NOTE: Webpack dev server requires this for CORS workaround.
|
||||||
|
corsRequestHeaders = "content-type" : corsRequestHeaders simpleCorsResourcePolicy
|
||||||
|
}
|
||||||
|
corsMiddleware = cors . const $ Just corsPolicy
|
||||||
|
|
||||||
|
-- Scripts stay cached for five minutes
|
||||||
|
agoraScripts' <- cachedFor (Just $ TimeSpec 300 0) agoraScripts
|
||||||
|
|
||||||
printf "[info] Running 'agora-scripts' on :%d\n" (Warp.getPort settings)
|
printf "[info] Running 'agora-scripts' on :%d\n" (Warp.getPort settings)
|
||||||
Warp.runSettings settings $ Servant.serve (Proxy @API) (pure . agoraScripts)
|
Servant.serve (Proxy @API) agoraScripts'
|
||||||
|
& corsMiddleware
|
||||||
|
& Warp.runSettings settings
|
||||||
|
|
||||||
-- | Create scripts from params.
|
-- | Create scripts from params.
|
||||||
agoraScripts :: ScriptParams -> AgoraScripts
|
agoraScripts :: ScriptParams -> AgoraScripts
|
||||||
|
|
@ -102,6 +95,8 @@ agoraScripts params =
|
||||||
, authorityTokenPolicyInfo = mkPolicyInfo (authorityTokenPolicy authorityToken)
|
, authorityTokenPolicyInfo = mkPolicyInfo (authorityTokenPolicy authorityToken)
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
|
-- This encodes the git revision of the server. It's useful for the caller
|
||||||
|
-- to be able to ensure they are compatible with it.
|
||||||
revision :: String
|
revision :: String
|
||||||
revision = $(gitBranch) <> "@" <> $(gitHash)
|
revision = $(gitBranch) <> "@" <> $(gitHash)
|
||||||
|
|
||||||
|
|
|
||||||
1
agora-scripts/Cache.hs
Normal file
1
agora-scripts/Cache.hs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
module Cache where
|
||||||
41
agora-scripts/Codec/Serialise/Orphans.hs
Normal file
41
agora-scripts/Codec/Serialise/Orphans.hs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||||
|
|
||||||
|
{- |
|
||||||
|
Module : Codec.Serialise.Orphans
|
||||||
|
Maintainer : emi@haskell.fyi
|
||||||
|
Description: Orphan instances for Serialising and Hashing Cardano types.
|
||||||
|
|
||||||
|
Orphan instances for Serialising and Hashing Cardano types.
|
||||||
|
-}
|
||||||
|
module Codec.Serialise.Orphans () where
|
||||||
|
|
||||||
|
import Codec.Serialise (Serialise, serialise)
|
||||||
|
import Data.Hashable (Hashable (hashWithSalt))
|
||||||
|
import Data.Tagged (Tagged (Tagged))
|
||||||
|
import PlutusLedgerApi.V1 (TxId, TxOutRef)
|
||||||
|
import PlutusLedgerApi.V1.Value (AssetClass, CurrencySymbol, TokenName)
|
||||||
|
import Types (ScriptParams)
|
||||||
|
|
||||||
|
deriving anyclass instance
|
||||||
|
Serialise TxOutRef
|
||||||
|
|
||||||
|
deriving anyclass instance
|
||||||
|
Serialise TxId
|
||||||
|
|
||||||
|
deriving anyclass instance
|
||||||
|
Serialise AssetClass
|
||||||
|
|
||||||
|
deriving anyclass instance
|
||||||
|
Serialise CurrencySymbol
|
||||||
|
|
||||||
|
deriving anyclass instance
|
||||||
|
Serialise TokenName
|
||||||
|
|
||||||
|
deriving newtype instance
|
||||||
|
Serialise a =>
|
||||||
|
Serialise (Tagged s a)
|
||||||
|
|
||||||
|
deriving anyclass instance Serialise ScriptParams
|
||||||
|
|
||||||
|
instance Hashable ScriptParams where
|
||||||
|
hashWithSalt s scriptParams = hashWithSalt s (serialise scriptParams)
|
||||||
41
agora-scripts/Data/Cache/Cached.hs
Normal file
41
agora-scripts/Data/Cache/Cached.hs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
{- | Module : API
|
||||||
|
Maintainer : emi@haskell.fyi
|
||||||
|
Description: API for script exporter.
|
||||||
|
|
||||||
|
API for script exporter.
|
||||||
|
-}
|
||||||
|
module Data.Cache.Cached (
|
||||||
|
cached,
|
||||||
|
cachedFor,
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Monad.IO.Class (MonadIO (liftIO))
|
||||||
|
import Data.Cache qualified as Cache
|
||||||
|
import Data.Functor ((<&>))
|
||||||
|
import Data.Hashable (Hashable)
|
||||||
|
import System.Clock (TimeSpec)
|
||||||
|
|
||||||
|
{- | 'cachedFor' but items last forever.
|
||||||
|
|
||||||
|
Uses a HashMap under the hood.
|
||||||
|
-}
|
||||||
|
cached :: (Monad m, MonadIO m, Hashable k, Ord k) => (k -> v) -> IO (k -> m v)
|
||||||
|
cached = cachedFor Nothing
|
||||||
|
|
||||||
|
{- | Create a cached version of a function tainting result with MonadIO context.
|
||||||
|
|
||||||
|
Results are cached dependent on the first argument, @'Maybe' 'TimeSpec'@.
|
||||||
|
|
||||||
|
Uses a HashMap under the hood.
|
||||||
|
-}
|
||||||
|
cachedFor :: (Monad m, MonadIO m, Hashable k, Ord k) => Maybe TimeSpec -> (k -> v) -> IO (k -> m v)
|
||||||
|
cachedFor t f =
|
||||||
|
Cache.newCache t <&> \cache k -> do
|
||||||
|
res <- liftIO $ Cache.lookup cache k
|
||||||
|
case res of
|
||||||
|
Nothing -> do
|
||||||
|
let v = f k
|
||||||
|
liftIO $ Cache.insert cache k v
|
||||||
|
pure v
|
||||||
|
Just v -> do
|
||||||
|
pure v
|
||||||
|
|
@ -7,9 +7,9 @@ Command line options for 'agora-scripts'.
|
||||||
-}
|
-}
|
||||||
module Options (Options (..), parseOptions) where
|
module Options (Options (..), parseOptions) where
|
||||||
|
|
||||||
|
import Network.Wai.Handler.Warp qualified as Warp
|
||||||
import Options.Applicative ((<**>))
|
import Options.Applicative ((<**>))
|
||||||
import Options.Applicative qualified as Opt
|
import Options.Applicative qualified as Opt
|
||||||
import qualified Network.Wai.Handler.Warp as Warp
|
|
||||||
|
|
||||||
data Options = Options
|
data Options = Options
|
||||||
{ port :: Warp.Port
|
{ port :: Warp.Port
|
||||||
|
|
@ -19,7 +19,8 @@ data Options = Options
|
||||||
opt :: Opt.Parser Options
|
opt :: Opt.Parser Options
|
||||||
opt =
|
opt =
|
||||||
Options
|
Options
|
||||||
<$> Opt.option Opt.auto
|
<$> Opt.option
|
||||||
|
Opt.auto
|
||||||
( Opt.long "port"
|
( Opt.long "port"
|
||||||
<> Opt.short 'p'
|
<> Opt.short 'p'
|
||||||
<> Opt.metavar "PORT"
|
<> Opt.metavar "PORT"
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,14 @@
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{- | Module : Scripts
|
||||||
|
Maintainer : emi@haskell.fyi
|
||||||
|
Description: Export scripts given configuration.
|
||||||
|
|
||||||
{- |
|
Export scripts given configuration.
|
||||||
Module : Scripts
|
|
||||||
Maintainer : emi@haskell.fyi
|
|
||||||
Description: Export scripts given configuration.
|
|
||||||
|
|
||||||
Export scripts given configuration.
|
|
||||||
-}
|
-}
|
||||||
module Main (main) where
|
module Scripts (main) where
|
||||||
|
|
||||||
import Options (parseOptions)
|
|
||||||
import API (runServer)
|
import API (runServer)
|
||||||
|
import Options (parseOptions)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main =
|
||||||
options <- parseOptions
|
parseOptions >>= runServer
|
||||||
|
|
||||||
runServer options
|
|
||||||
|
|
|
||||||
42
agora-scripts/Types.hs
Normal file
42
agora-scripts/Types.hs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{- |
|
||||||
|
Module : Types
|
||||||
|
Maintainer : emi@haskell.fyi
|
||||||
|
Description: Param and script types for generation.
|
||||||
|
|
||||||
|
Param and script types for generation.
|
||||||
|
-}
|
||||||
|
module Types (ScriptParams (..), AgoraScripts (..)) where
|
||||||
|
|
||||||
|
import Agora.SafeMoney (GTTag)
|
||||||
|
import Agora.ScriptInfo (PolicyInfo, ValidatorInfo)
|
||||||
|
import Data.Aeson qualified as Aeson
|
||||||
|
import Data.Tagged (Tagged)
|
||||||
|
import GHC.Generics qualified as GHC
|
||||||
|
import PlutusLedgerApi.V1 (TxOutRef)
|
||||||
|
import PlutusLedgerApi.V1.Value (AssetClass)
|
||||||
|
|
||||||
|
-- | Params required for creating script export.
|
||||||
|
data ScriptParams where
|
||||||
|
ScriptParams ::
|
||||||
|
{ governorInitialSpend :: TxOutRef
|
||||||
|
, gtClassRef :: Tagged GTTag AssetClass
|
||||||
|
, maximumCosigners :: Integer
|
||||||
|
} ->
|
||||||
|
ScriptParams
|
||||||
|
deriving anyclass (Aeson.ToJSON, Aeson.FromJSON)
|
||||||
|
deriving stock (Show, Eq, GHC.Generic, Ord)
|
||||||
|
|
||||||
|
-- | Scripts that get exported.
|
||||||
|
data AgoraScripts = AgoraScripts
|
||||||
|
{ gitRev :: String
|
||||||
|
, 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)
|
||||||
16
agora.cabal
16
agora.cabal
|
|
@ -235,18 +235,26 @@ executable agora-scripts
|
||||||
main-is: Scripts.hs
|
main-is: Scripts.hs
|
||||||
hs-source-dirs: agora-scripts
|
hs-source-dirs: agora-scripts
|
||||||
other-modules:
|
other-modules:
|
||||||
Options
|
|
||||||
API
|
API
|
||||||
|
Codec.Serialise.Orphans
|
||||||
|
Data.Cache.Cached
|
||||||
|
Options
|
||||||
|
Types
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, agora
|
, agora
|
||||||
|
, cache
|
||||||
|
, clock
|
||||||
, gitrev
|
, gitrev
|
||||||
|
, hashable
|
||||||
|
, http-types
|
||||||
, optparse-applicative
|
, optparse-applicative
|
||||||
|
, prettyprinter
|
||||||
, servant
|
, servant
|
||||||
, servant-server
|
, servant-server
|
||||||
, warp
|
|
||||||
, wai
|
, wai
|
||||||
, http-types
|
, wai-cors
|
||||||
, prettyprinter
|
, warp
|
||||||
|
|
||||||
executable agora-purescript-bridge
|
executable agora-purescript-bridge
|
||||||
import: lang, deps, exe-opts
|
import: lang, deps, exe-opts
|
||||||
|
|
|
||||||
14
flake.nix
14
flake.nix
|
|
@ -140,11 +140,15 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
applyDep = pkgs: o:
|
applyDep = pkgs: o:
|
||||||
let h = myhackage pkgs.system o.compiler-nix-name; in
|
let
|
||||||
(plutarch.applyPlutarchDep pkgs o) // {
|
h = myhackage pkgs.system o.compiler-nix-name;
|
||||||
modules = haskellModules ++ [ h.module ] ++ (o.modules or [ ]);
|
o' = (plutarch.applyPlutarchDep pkgs o);
|
||||||
extra-hackages = [ (import h.hackageNix) ] ++ (o.extra-hackages or [ ]);
|
in
|
||||||
extra-hackage-tarballs = { _xNJUd_plutarch-hackage = h.hackageTarball; } // (o.extra-hackage-tarballs or { });
|
o' // rec {
|
||||||
|
modules = haskellModules ++ [ h.module ] ++ (o'.modules or [ ]);
|
||||||
|
extra-hackages = [ (import h.hackageNix) ] ++ (o'.extra-hackages or [ ]);
|
||||||
|
extra-hackage-tarballs = { _xNJUd_plutarch-hackage = h.hackageTarball; };
|
||||||
|
cabalProjectLocal = (o'.cabalProjectLocal or "") + " , cache >= 0.1.3.0";
|
||||||
};
|
};
|
||||||
|
|
||||||
projectForGhc = compiler-nix-name: system:
|
projectForGhc = compiler-nix-name: system:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue