Skip to Content
Scalus Club is now open! Join us to get an early access to new features 🎉

Using Macros

Scalus provides a set of macros that can be used to simplify your code.

Inlining constants

inline

Scalus can inline constants in your scripts, which is a powerful optimization technique. When you mark a parameter as inline, its value is directly embedded in the compiled code rather than being passed as a parameter at runtime. This reduces script size and execution costs, which is particularly valuable for on-chain code where every byte counts.

For example, when you inline a ByteString constant like a public key hash, it appears directly in the compiled SIR as a literal value (#deadbeef) rather than being computed or passed as a parameter.

import scalus.*, Compiler.*, builtin.{Data, Builtins, ByteString, given}, Builtins.*, ByteString.given inline def validator(inline pubKeyHash: ByteString)(datum: Data, redeemer: Data, ctxData: Data) = verifyEd25519Signature(pubKeyHash, datum.toByteString, redeemer.toByteString) val script = compile: validator(hex"deadbeef")

… generates the following SIR code, where you can see the inlined constant #deadbeef directly in the compiled output:

{λ datum redeemer ctxData -> verifyEd25519Signature(#deadbeef, unBData(datum), unBData(redeemer)) }

Conditional code generation

TODO: Check using

The using macro allows you to conditionally include or exclude code at compile time based on configuration parameters. This is particularly useful for creating separate debug and production versions of your validators.

dbg - Trace calls generation

import scalus.*, Compiler.*, builtin.Data, builtin.Builtins // the `dbg` macro will generate `trace` calls only if the `debug` flag is set to `true` inline def dbg[A](msg: String)(a: A)(using debug: Boolean): A = inline if debug then Builtins.trace(msg)(a) else a inline def validator(using debug: Boolean)(datum: Data, redeemer: Data, ctxData: Data) = dbg("datum")(datum) val releaseScript = compile(validator(using false)) // {λ datum redeemer ctxData -> datum } val debugScript = compile(validator(using true)) // {λ datum redeemer ctxData -> trace("datum", datum) }

Here, the releaseScript will not contain any trace calls, while the debugScript will contain them. This demonstrates how Scalus can conditionally include or exclude code at compile time based on configuration parameters.

The conditional code is evaluated during compilation, so there’s zero runtime overhead for disabled features.

Last updated on