Tech Drips #1: Optimizing Plutus script to reduce fees and increase throughput

Minswap Labs
Minswap English
Published in
3 min readNov 29, 2021

Tech Drips is Minswap’s new blog post series focusing on the technical aspects of building on Cardano. This series is one of our efforts towards open knowledge-sharing and fostering the Cardano developer ecosystem.

With the current surging popularity and demand for Cardano, it is more important than ever to think about optimizing Plutus scripts since every DApp optimization will reduce the end user’s fees and leave more block space for other transactions. Following a recent discussion, we would also like to contribute our learnings regarding the topic. These techniques are independently discovered by the Minswap smart contract team and have been used in most of our internal contracts. While low-level optimization is almost always preferred to allow developers to write contracts in a natural and idiomatic way, our tips and techniques will allow any DApp developer to optimize their contracts today and save block space and fees. They will also be helpful for DApps that are performance-sensitive.

All examples in this post can be seen on GitHub: https://github.com/minswap/plutus-optimization-example

How to analyze script size and costs will depend on which toolchain you are using:

Avoid deserializing unnecessary ScriptContext fields

Deserializing ScriptContext from BuiltinData has some cost. The cost will increase linearly with the number of inputs, outputs, and assets in the transaction. However, not all scripts use all fields in the ScriptContext and we can create a custom ScriptContext type and use BuiltinData for the fields we want to skip deserializing. Note that since a record-syntax type definition is serialized as Constr Integer [Data], we need to specify all fields in the correct order even if we want to skip them. For example, a script that only needs to know the transaction outputs can have its custom ScriptContext defined like this:

data TxInfo = TxInfo
{ txInfoInputs :: BuiltinData,
txInfoOutputs :: [TxOut],
txInfoFee :: BuiltinData,
txInfoMint :: BuiltinData,
txInfoDCert :: BuiltinData,
txInfoWdrl :: BuiltinData,
txInfoValidRange :: BuiltinData,
txInfoSignatories :: BuiltinData,
txInfoData :: BuiltinData,
txInfoId :: BuiltinData
}
deriving stock (Generic, Haskell.Eq)
data CustomScriptContext = CustomScriptContext {scriptContextTxInfo :: TxInfo, scriptContextPurpose :: ScriptPurpose}
deriving stock (Generic, Haskell.Eq)

After defining a custom type for ScriptContext, we will use the normal mkValidatorScript instead of mkTypedValidator, and then use unsafeFromBuiltinData to manually deserialize to the custom ScriptContext.

Use Bang Pattern in let-binding

Bang Pattern is a Haskell language feature that allows forcing evaluation of lazy expressions. Even though Plutus Core is a strict language, we have found that using Bang Pattern in let-binding from Haskell code will yield smaller script size and cost. The reduction will be more noticeable if the name binding is used in multiple places.

Example:

let
!outVal = CC.txOutValue ownOutput
!amountA = assetClassValueOf outVal mdCoinA
!amountB = assetClassValueOf outVal mdCoinB

Avoid exhaustive pattern-matching in error cases

Missing pattern matches in Plutus will result in an error () call in the compiled code. That is why if you find yourself writing this:

case condition of
pattern1 -> doSomething
pattern2 -> traceError "boom"
_ -> traceError "boom"

then you can remove the traceError lines:

case condition of
pattern1 -> doSomething

and the behavior will be the same but we save some compiled script size. The only downside of this method is that there wouldn’t be any trace in PAB logs.

The amount of transaction size and cost reduced will vary greatly based on the DApp architecture. That is why after publishing this article, we would like to hear the community’s feedback on whether these methods can be successfully applied to their DApps. It has only been 3 months since smart contract launched on Cardano but the speed at which the ecosystem is evolving is truly fascinating. That is precisely why we believe that every kilobyte or execution unit saved will contribute greatly to the normal user’s fees and the overall throughput of the network.

--

--

Minswap Labs
Minswap English

Minswap is the multi-pool decentralized exchange on the Cardano blockchain: https://minswap.org