-
Notifications
You must be signed in to change notification settings - Fork 4
🧪GHCi Tutorials : Testing `Vesting.hs` Interactively Using GHCi
Goal: Learn to load, inspect, and test your Plutus
Vesting.hsmodule directly inside GHCi — exploring every type, conversion, and value that composes yourVestingDatum.
- 🎯 Goal & Prerequisites
- ⚙️ Project Setup &
cabal repl - 🧪 GHCi Quick Primer
- 📦 What Each Import Gives You (Expanded)
- 🧰 Working with Bytes — From String → ByteString → BuiltinByteString
- 🔤 Keys & Time —
PubKeyHashandPOSIXTime - 🏗️ Building a
VestingDatumValue - ⚡ One-Liners & REPL Tricks
- 🔍 Type and Info Commands (
:t,:i) - 🧯 Common Pitfalls & Fixes
- 📚 Glossary
You’ll learn how to:
- Start GHCi using
cabal repl - Import Plutus modules interactively
- Convert between text, bytes, and Plutus types
- Construct and inspect a full
VestingDatumrecord
You need:
-
A Plutus project (like
wspace) withVesting.hscontaining:data VestingDatum = VestingDatum { beneficiary :: PubKeyHash , deadline :: POSIXTime , code :: Integer } deriving (Show)
-
GHC 8.10.7
-
Plutus libraries installed
Start your REPL from the project root:
cabal replOutput should look like:
GHCi, version 8.10.7...
Ok, six modules loaded.
Optional session settings:
:set prompt "> "
:set -XOverloadedStrings
OverloadedStringsmakes"abc"polymorphic — can act asString,Text, or evenBuiltinByteStringdepending on context.
| Command | Description |
|---|---|
:load Module or :l Module
|
Load or reload a file |
:r |
Reload current modules |
:show modules |
List all loaded modules |
:t expr |
Show type of an expression |
:i Name |
Show detailed info (type, constructors, instances) |
:set -XExtension |
Enable a language extension |
:q |
Quit GHCi |
🧠 Pro tip: GHCi prints every expression by doing
print it. That’s why you needderiving (Show)to see values.
Let’s deeply understand each import that powers your vesting interaction.
Purpose: Convert between human-readable text and raw bytes (ByteString).
Why: Plutus and Base16 operate on ByteString, not [Char].
| Function | Type | Description |
|---|---|---|
C.pack |
String -> ByteString |
Converts "Hello" to bytes [72,101,108,108,111]. |
C.unpack |
ByteString -> String |
Reverses pack, decoding bytes back into readable text. |
Example:
import qualified Data.ByteString.Char8 as C
let rawBytes = C.pack "Bernard"
C.unpack rawBytes
-- "Bernard"🔎 Why Char8?
It encodes each Char as one byte (ASCII), ideal for deterministic blockchain data.
Purpose: Encode/decode hexadecimal text to/from ByteString.
Why: Cardano addresses and pubkey hashes are usually in hex form.
| Function | Type | Description |
|---|---|---|
B16.decode |
ByteString -> Either (ByteString, Int) ByteString |
Converts a hex string (like "deadbeef") to binary bytes. Returns Right on success, Left on failure. |
Example:
-- example bech32Addr : addr_test1qqyk7gn3kxmdca42t2mkwmfkf5j54fyyh02ldaln267tu8tm3x27l4euuhcvdun55j6sedp5rv7wt0n0lvx88t20rn9qvaksx7
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Base16 as B16
let (Right raw) = B16.decode (C.pack "096f2271b1b6dc76aa5ab7676d364d254aa484bbd5f6f7f356bcbe1d")Why Base16?
B16.decode transforms a visible hash into its true underlying byte pattern for on-chain use.
Purpose: Bridge normal Haskell ByteString and Plutus BuiltinByteString.
| Name | Type | Description |
|---|---|---|
toBuiltin |
ByteString -> BuiltinByteString |
Converts standard bytes into the Plutus built-in type. |
fromBuiltin |
BuiltinByteString -> ByteString |
Converts built-in bytes back to normal bytes for debugging. |
BuiltinByteString |
type | The native byte array type used inside Plutus scripts. |
Example:
import PlutusTx.Builtins (toBuiltin, fromBuiltin)
let plutusBytes = toBuiltin raw
C.unpack (fromBuiltin plutusBytes)🧠 Why convert?
On-chain scripts use BuiltinByteString for deterministic operations — no lazy I/O, no hidden state.
Defines all the ledger-level Plutus data structures.
For this tutorial, you only need two newtypes: PubKeyHash and POSIXTime.
- Represents a wallet’s payment key hash.
- Wraps a
BuiltinByteStringfor type safety. - Required for
VestingDatum.beneficiary.
Usage:
import Plutus.V2.Ledger.Api (PubKeyHash(..))
let pkh = PubKeyHash plutusBytesCheck its constructor:
:t PubKeyHash
-- PubKeyHash :: BuiltinByteString -> PubKeyHash- Represents a time on the blockchain (milliseconds since Unix epoch).
- Used in deadlines, validity intervals, etc.
Usage:
import Plutus.V2.Ledger.Api (POSIXTime(..))
let t = POSIXTime 1760897124Check its type:
:t POSIXTime
-- POSIXTime :: Integer -> POSIXTime"096f22..." (String)
│ C.pack
▼
ByteString
│ B16.decode
▼
Raw Bytes (ByteString)
│ toBuiltin
▼
BuiltinByteString
│ PubKeyHash
▼
PubKeyHash
Each layer wraps the previous one, ensuring data integrity and Plutus compatibility.
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Base16 as B16
import PlutusTx.Builtins (toBuiltin)
let (Right raw) = B16.decode (C.pack "096f22...be1d")
let bsBuiltin = toBuiltin rawVerify:
:t bsBuiltin
-- bsBuiltin :: BuiltinByteStringimport Plutus.V2.Ledger.Api (PubKeyHash(..), POSIXTime(..))
let pkh = PubKeyHash bsBuiltin
let deadline = POSIXTime 1760897124import Vesting
let vd = VestingDatum
{ beneficiary = pkh
, deadline = deadline
, code = 58443
}If VestingDatum derives Show:
vdPrints:
VestingDatum {beneficiary = 096f22..., deadline = POSIXTime {getPOSIXTime = 1760897124}, code = 58443}
Compact one-liner:
let (Right raw)=B16.decode(C.pack"096f22...be1d");let vd=VestingDatum{beneficiary=PubKeyHash(toBuiltin raw),deadline=POSIXTime 1760897124,code=58443}Reload after edits:
:r
View module exports:
:browse Plutus.V2.Ledger.Api
| Command | Example | Result |
|---|---|---|
:t expr |
:t PubKeyHash |
shows function signature |
:i Type |
:i BuiltinByteString |
shows constructors, instances |
:show modules |
– | lists all modules loaded |
| Issue | Cause | Fix |
|---|---|---|
"abc" :: BuiltinByteString fails |
GHCi string literals are [Char]
|
Use toBuiltin (C.pack "abc")
|
No instance for (Show VestingDatum) |
GHCi can’t print custom types | Add deriving (Show)
|
Couldn't match expected type PubKeyHash |
You passed raw bytes | Use PubKeyHash (toBuiltin raw)
|
Base16 expects ByteString |
Gave it [Char]
|
Wrap with C.pack
|
Parse error using =
|
Haskell record syntax uses { field = val, ... }
|
Correct to VestingDatum { field1 = ..., field2 = ... }
|
| Term | Meaning |
|---|---|
| ByteString | Efficient raw byte array for binary data. |
| BuiltinByteString | Plutus built-in byte array used on-chain. |
| toBuiltin / fromBuiltin | Convert between Haskell and Plutus bytes. |
| Base16 (Hex) | Encodes binary data as readable hexadecimal. |
| PubKeyHash | Wallet/public-key identifier in Plutus. |
| POSIXTime | Blockchain-safe timestamp wrapper. |
| VestingDatum | On-chain data type specifying vesting details. |
:t / :i |
Show type / show info in GHCi. |
| OverloadedStrings | Extension for polymorphic string literals. |
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Base16 as B16
import PlutusTx.Builtins (toBuiltin)
import Plutus.V2.Ledger.Api (PubKeyHash(..), POSIXTime(..))
import Vesting
let (Right raw) = B16.decode (C.pack "096f2271b1b6dc76aa5ab7676d364d254aa484bbd5f6f7f356bcbe1d")
let pkh = PubKeyHash (toBuiltin raw)
let vd = VestingDatum { beneficiary = pkh, deadline = POSIXTime 1760897124, code = 58443 }
vdBernard Sibanda is a global Technology Entrepreneur, Web3 and Software Consultant with a deep focus on Cardano Blockchain, Midnight and Community building.
Key Positions:
- Founder, CTO, Developer Advocate cohort #1, Fullstake Developer, Cardano Ambassador, Catalyst Project Manager, DREP-WIMS:
- Co-founder of ABL Tech and Cardano Africa Live
- EBU-certified Plutus Pioneer (Plutus/Haskell)
- Cohort #1 Plutus Pioneer Developer
- Catalyst Community Reviewer & Funded Projects Manager
-
DRep for WIMS-Cardano (ID:
drep1yguj8zu48n99pv70yl6ckzt9hdgjy8yjnlqs2uyzcpafnjgu4vkul) - Intersect Developer Advocate
- Intersect Committe Member 2025-2026
- Cardano Marketer,Promoter and blogger
- Cardano Open Source Contributor
- Cardano communities and events organizer and builder
- Cardano Ambassador for South Africa
Official links:
- Stablecoins Dex
- Coxygen Global Universities
- WIMS Cardano Global
- Cardano Africa Live
- WIMS Cardano Videos
- Cardano Smart Contract Videos
- Fullstack IT Consulting
Social links: