I have a script that is developed in Plutus Playground. It is working well and now I want to deploy it to the Cardano blockchain via cardano-cli.

Following this answer, I have to use cabal to turn my Haskell script (.hs) into a plutus (.plutus) file. And then send it along with a transaction to the blockchain. The answer is vague and provides no details. I especially need to know how to configure .cabal file, dependencies, among other things. I find no other resource/tutorial that shows how it is done.

Question: How to turn (compile) my “script.hs” into “script.plutus”?

I am aware of this example by IOHK. But now I need to apply to own script and configurations.


3 Answers 3


Another way is to use a separate Utils.hs file (remember add it in your your-app.cabal file for config) for utility fucntions, example:

dataToScriptData :: Data -> ScriptData
dataToScriptData (Constr n xs) = ScriptDataConstructor n $ dataToScriptData <$> xs
dataToScriptData (Map xs)      = ScriptDataMap [(dataToScriptData x, dataToScriptData y) | (x, y) <- xs]
dataToScriptData (List xs)     = ScriptDataList $ dataToScriptData <$> xs
dataToScriptData (I n)         = ScriptDataNumber n
dataToScriptData (B bs)        = ScriptDataBytes bs

writeJSON :: PlutusTx.ToData a => FilePath -> a -> IO ()
writeJSON file = LBS.writeFile file . encode . scriptDataToJson ScriptDataJsonDetailedSchema . dataToScriptData . PlutusTx.toData

writeUnit :: IO ()
writeUnit = writeJSON "scripts/unit.json" ()

-- For validator:
writeValidator :: Plutus.Validator -> IO (Either (FileError ()) ())
writeValidator = writeValidator "scripts/demoContract.plutus" . validator

-- For minting policy:
writeMintingPolicy :: Plutus.MintingPolicy -> IO (Either (FileError ()) ())
writeMintingPolicy  = writeFileTextEnvelope @(PlutusScript PlutusScriptV1) "scripts/my-minting-script.plutus" Nothing . PlutusScriptSerialised . SBS.toShort . LBS.toStrict . serialise . Plutus.getMintingPolicy

Then pass your minting policy or validator in the above functions then you would get a script output.

Example of my implementation on a validator:

strToPpkh :: String -> Plutus.PaymentPubKeyHash
strToPpkh = Plutus.PaymentPubKeyHash . Plutus.PubKeyHash . stringToBuiltinByteString 

tupleToAssetClass :: (String, String) -> AssetClass
tupleToAssetClass (cs, tn) = AssetClass (CurrencySymbol $ stringToBuiltinByteString cs, TokenName $ stringToBuiltinByteString tn)

makeParam :: (String, String) -> String -> (String, String) -> AppParam
makeParam ca fc tt = AppParam {
    cContractAsset = tupleToAssetClass ca
    , cFeeCollector  = strToPpkh fc
    , cTT            = tupleToAssetClass tt 

writeSimplifiedValidator :: (String, String) -> String -> (String, String) -> IO (Either (FileError ()) ())
writeSimplifiedValidator ca fc tt = writeValidator "scripts/demoContract.plutus" $ Simplified.validator $ makeParam ca fc tt

An excessive import list as below, its from PPP lecture with wallet implementation as well, you could filtered out those not used for your own purposes:

{-# LANGUAGE GADTs            #-}
{-# LANGUAGE TypeApplications #-}

module Utils.Utils where

import           Cardano.Api                 as API
import           Cardano.Api.Shelley         (Address (..), PlutusScript (..))
import           Cardano.Crypto.Hash.Class   (hashToBytes)
import           Cardano.Ledger.Credential   as Ledger
import           Cardano.Ledger.Crypto       (StandardCrypto)
import           Cardano.Ledger.Hashes       (ScriptHash (..))
import           Cardano.Ledger.Keys         (KeyHash (..))
import           Codec.Serialise             (serialise)
import           Data.Aeson                  (decode, encode)
import qualified Data.ByteString.Char8       as BS8
import qualified Data.ByteString.Lazy        as LBS
import qualified Data.ByteString.Short       as SBS
import           Data.Maybe                  (fromJust, fromMaybe)
import           Data.String                 (IsString (..))
import           Data.Text                   (pack)
import           Plutus.PAB.Webserver.Types  (ContractActivationArgs (..))
import           Plutus.V1.Ledger.Credential as Plutus
import           Plutus.V1.Ledger.Crypto     as Plutus
import           Plutus.V1.Ledger.Value      (TokenName (..))
import           PlutusTx                    (Data (..))
import qualified PlutusTx
import           PlutusTx.Builtins           (toBuiltin)
import           PlutusTx.Builtins.Internal  (BuiltinByteString (..))
import qualified Ledger                      as Plutus
import           Ledger.Value              
import           Wallet.Emulator.Wallet      (WalletId (..), Wallet (..))
import           Wallet.Types                (ContractInstanceId (..))
import           PlutusTx.Builtins.Class

import           MyApp.Onchain
import           MyApp.Types
import           MyToken.Onchain
  • I was stuck for a while, getting my head around things. But yeah this is the way to go. Thanks!
    – Adam
    Oct 6, 2022 at 0:36

Take a look at this example: (https://github.com/Apexaverse-metaverse/P2E/blob/main/scripts/mint-token-cli.sh#L22), is a bit clunky but it works:

Using cabal repl. I call writePolicyFile function from https://github.com/Apexaverse-metaverse/P2E/blob/main/src/Deploy.hs#L58. This function builds the policy UPLC using hard-coded params, serialize it to plutus format and save it. Then, in the bash script, the tx is built and submitted using cardano-cli.

  • This works. Thanks!
    – Adam
    Oct 6, 2022 at 0:45

You can base your cabal files and project from plutus-apps next-node branch. See here: https://github.com/input-output-hk/plutus-apps/blob/next-node/cabal.project

I have an example repo you can you as guideline here: https://github.com/james-iohk/plutus-scripts

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.