From 1731fc491a86a9d4c9d55e8ce01cb072078e9e0c Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 12:15:41 +0100 Subject: [PATCH 1/9] preparing v8 release --- CHANGELOG.md | 10 +++ README.md | 93 ++++++++++++++---------- cooked-validators.cabal | 4 +- flake.lock | 22 +++--- flake.nix | 154 +++++++++++++++++++++------------------- package.yaml | 2 +- 6 files changed, 160 insertions(+), 125 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b398ebea..e5c7a0dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ ### Added +### Removed + +### Changed + +### Fixed + +## [[8.0.0]](https://github.com/tweag/cooked-validators/releases/tag/v8.0.0) - 2026-01-19 + +### Added + - `viewByRef` and `previewByRef` which call `txSkelOutByRef` and apply a getter and an affine fold on it, respectively. - Optics working on values in `Cooked.Skeleton.Output` diff --git a/README.md b/README.md index 675a9a62..d227c11e 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,55 @@ # [Cooked Validators](https://github.com/tweag/cooked-validators/) -Copyright Tweag I/O 2025 - -`cooked-validators` is a Haskell library to conveniently and efficiently write -off-chain code for Cardano smart contracts. This offchain code will be -specifically geared to testing and auditing the smart contract in question with -further builtin capabilities of the library. - -In particular, `cooked-validators` allows the user to: -- interact with smart contracts written in Plutus or any other language that - compiles to [UPLC](https://plutonomicon.github.io/plutonomicon/uplc), like for - example [Plutarch](https://github.com/Plutonomicon/plutarch-plutus) or - [Aiken](https://aiken-lang.org/), by loading contracts from byte strings -- define transactions in a high level, type-retaining data structure -- submit transactions for validation, while automatically taking care of missing - inputs and outputs, balancing, minimum-Ada constraints, collaterals and fees -- construct sequences of transactions in an easy-to-understand abstraction of - "the blockchain", which can be instantiated to different actual - implementations -- run sequences of transactions in a simulated blockchain -- apply "tweaks" to transactions right before submitting them, where "tweaks" - are modifications that are aware of the current state of the simulated - blockchain -- compose and deploy tweaks with flexible idioms inspired by linear temporal - logic, in order to turn one sequence of transactions into many sequences that - might be useful test cases, generalized in - [Graft](https://github.com/tweag/graft) -- deploy automated attacks over existing sequences of transactions, such as - datum hijacking or double satisfaction attacks, in an attempt to uncover - vulnerabilities - -You are free to copy, modify, and distribute `cooked-validators` under the terms -of the MIT license. We provide `cooked-validators` as a research prototype under -active development, and it comes _as is_ with no guarantees whatsoever. Check -the [license](LICENSE) for details. +Copyright Tweag I/O 2026 + +`cooked-validators` is a Haskell library for writing reliable, concise, and +expressive off-chain code for Cardano smart contracts, with a primary focus on +testing, auditing, and behavioral exploration. + +It allows you to describe transactions at a high level (via transaction +skeletons) and automatically turn them into complete, valid transactions by +handling all mechanical aspects such UTxO selection, balancing, minimum-Ada +constraints, collaterals or fees. + +The library is designed to: +- drastically reduce off-chain boilerplate, +- make test scenarios more readable and maintainable, +- facilitate adversarial testing and vulnerability discovery. + +## Core features + +With `cooked-validators`, you can: +- Interact with smart contracts written in Plutus or any language that compiles +to [UPLC](https://plutonomicon.github.io/plutonomicon/uplc), such as +[Plutarch](https://github.com/Plutonomicon/plutarch-plutus) or +[Aiken](https://aiken-lang.org/), by loading contracts from bytestrings. +- Define transactions using a high-level, type-preserving data structure. +- Submit transactions for validation while the library automatically: + * fills in missing inputs and outputs, + * performs balancing, + * enforces minimum-Ada constraints, + * computes and attaches optimal collaterals and fees, + * automatically adds script witnesses, including from reference inputs. +- Construct sequences of transactions in a clear, implementation-independent + abstraction of the blockchain. +- Run transaction sequences in an emulated blockchain. +- Apply tweaks to transactions just before submission, where tweaks are + modifications aware of the current blockchain state. +- Compose and deploy tweaks on sequences of transactions using idioms inspired + by linear temporal logic. +- Deploy automated attacks on existing transaction sequences, such as datum + hijacking or double satisfaction attacks, to uncover vulnerabilities. +- Express expected outcomes of runs in a precise and declarative way, for + example by: + * specifying the expected number of outcomes in case branching occurred, + * asserting exact error messages in case of failure, + * ensuring a specific event was triggered during the run, + * checking the assets present at a given address. ## How to integrate `cooked-validators` in a project To use `cooked-validators`, you need -- [GHC](https://www.haskell.org/ghc/download_ghc_9_6_6.html) version 9.6.6 +- [GHC](https://www.haskell.org/ghc/download_ghc_9_6_7.html) version 9.6.7 - [Cabal](https://www.haskell.org/cabal) version 3.10 or later 1. `cooked-validators` depends on @@ -59,7 +70,7 @@ the `packages` stanza. subdir: . ``` - where `myTag` is either a commit hash in the repo, or a tag, such as v7.0.0 + where `myTag` is either a commit hash in the repo, or a tag, such as v8.0.0 (see [available releases](https://github.com/tweag/cooked-validators/releases)). @@ -112,9 +123,6 @@ the `packages` stanza. automated balancing mechanism and associated options (including options revolving around fees and collaterals). -- The [CONWAY](doc/CONWAY.md) file describes the Conway features that are - currently supported by `cooked-validators`. - - The [OPTICS](doc/OPTICS.md) file describes our usage of optics to navigate our data structures. @@ -138,3 +146,10 @@ the `packages` stanza. - `cooked-validators` comes with a [template repository](https://github.com/tweag/cooked-template) which can be used to develop offchain code and/or audit code with the tool. + +## License + +You are free to copy, modify, and distribute `cooked-validators` under the terms +of the MIT license. We provide `cooked-validators` as a research prototype under +active development, and it comes _as is_ with no guarantees whatsoever. Check +the [license](LICENSE) for details. diff --git a/cooked-validators.cabal b/cooked-validators.cabal index a4f40571..fe1b1774 100644 --- a/cooked-validators.cabal +++ b/cooked-validators.cabal @@ -1,11 +1,11 @@ cabal-version: 3.4 --- This file has been generated from package.yaml by hpack version 0.38.2. +-- This file has been generated from package.yaml by hpack version 0.38.3. -- -- see: https://github.com/sol/hpack name: cooked-validators -version: 7.0.0 +version: 8.0.0 license: MIT license-file: LICENSE build-type: Simple diff --git a/flake.lock b/flake.lock index e5a6762f..60d8f979 100644 --- a/flake.lock +++ b/flake.lock @@ -3,15 +3,15 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1761588595, - "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", - "owner": "edolstra", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", "repo": "flake-compat", - "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { - "owner": "edolstra", + "owner": "NixOS", "repo": "flake-compat", "type": "github" } @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1766062740, - "narHash": "sha256-U9KVTNs7PvyND7gisDMiluOfwT5hvOlMH2LTYfAYpNk=", + "lastModified": 1768817753, + "narHash": "sha256-WaULpLu8QV07UNq3XUvvS/z/YHe34OoC32C////5EmE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6dc87b326cef973e51ed3d2ffbdbe6240917a7be", + "rev": "dda42211b8e9b4216aab429a24008215c6870b65", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1765911976, - "narHash": "sha256-t3T/xm8zstHRLx+pIHxVpQTiySbKqcQbK+r+01XVKc0=", + "lastModified": 1767281941, + "narHash": "sha256-6MkqajPICgugsuZ92OMoQcgSHnD6sJHwk8AxvMcIgTE=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27", + "rev": "f0927703b7b1c8d97511c4116eb9b4ec6645a0fa", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4fa9ba99..2d743bce 100644 --- a/flake.nix +++ b/flake.nix @@ -4,8 +4,15 @@ inputs.pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix"; inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs"; - outputs = { self, nixpkgs, flake-utils, pre-commit-hooks }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + pre-commit-hooks, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = nixpkgs.legacyPackages.${system}; hpkgs = pkgs.haskell.packages.ghc96; @@ -15,21 +22,20 @@ ## is due to a bug where older processors (>= 10 years) ## would not be supported. This should not change anything ## on newer machines. This could be revised in the future. - blst-portable = pkgs.blst.overrideAttrs (_: _: { - buildPhase = '' - runHook preBuild - ./build.sh -shared -D__BLST_PORTABLE__ ${ - pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows - "flavour=mingw64" - } - runHook postBuild - ''; - }); + blst-portable = pkgs.blst.overrideAttrs ( + _: _: { + buildPhase = '' + runHook preBuild + ./build.sh -shared -D__BLST_PORTABLE__ ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows "flavour=mingw64"} + runHook postBuild + ''; + } + ); pre-commit = pre-commit-hooks.lib.${system}.run { src = ./.; hooks = { - nixfmt-classic.enable = true; + nixfmt.enable = true; ormolu.enable = true; hpack.enable = true; }; @@ -45,75 +51,79 @@ ## for more information. }; }; - in { - formatter = pkgs.nixfmt-classic; + in + { + formatter = pkgs.nixfmt; - devShells = let - ## The minimal dependency set to build the project with `cabal`. - buildInputs = [ - blst-portable - pkgs.pkg-config - pkgs.glibcLocales - pkgs.zlib - pkgs.libsodium - pkgs.secp256k1 - pkgs.lmdb - hpkgs.ghc - hpkgs.cabal-install - ]; + devShells = + let + ## The minimal dependency set to build the project with `cabal`. + buildInputs = [ + blst-portable + pkgs.pkg-config + pkgs.glibcLocales + pkgs.zlib + pkgs.libsodium + pkgs.secp256k1 + pkgs.lmdb + hpkgs.ghc + hpkgs.cabal-install + ]; - ## Folders in which to find ".so" files - LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath [ - pkgs.xz - pkgs.zlib - pkgs.lmdb - pkgs.openssl_3_6 - pkgs.postgresql # For cardano-node-emulator - pkgs.openldap # For freer-extras‽ - pkgs.libsodium - pkgs.secp256k1 - pkgs.lmdb - blst-portable - ]; + ## Folders in which to find ".so" files + LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath [ + pkgs.xz + pkgs.zlib + pkgs.lmdb + pkgs.openssl_3_6 + pkgs.postgresql # For cardano-node-emulator + pkgs.openldap # For freer-extras‽ + pkgs.libsodium + pkgs.secp256k1 + pkgs.lmdb + blst-portable + ]; - LANG = "C.UTF-8"; + LANG = "C.UTF-8"; - in { - ci = pkgs.mkShell { - inherit buildInputs; - inherit LD_LIBRARY_PATH; - inherit LANG; - }; + in + { + ci = pkgs.mkShell { + inherit buildInputs; + inherit LD_LIBRARY_PATH; + inherit LANG; + }; - default = pkgs.mkShell { - buildInputs = buildInputs ++ [ - pkgs.hpack - pkgs.hlint - hpkgs.ormolu - hpkgs.haskell-language-server - ]; + default = pkgs.mkShell { + buildInputs = buildInputs ++ [ + pkgs.hpack + pkgs.hlint + hpkgs.ormolu + hpkgs.haskell-language-server + ]; - inherit LD_LIBRARY_PATH; - inherit LANG; + inherit LD_LIBRARY_PATH; + inherit LANG; - # In addition to the pre-commit hooks, this redefines a cabal - # command that gets rid of annoying "Writing: .....*.html" output - # when running cabal test. - shellHook = pre-commit.shellHook + '' - function cabal() { - if [ "$1" != "test" ]; then - command cabal "$@" - else - command cabal --test-option=--color=always "$@" | grep -vE --color=never "^Writing:.*html$" - fi - } - export -f cabal - ''; + # In addition to the pre-commit hooks, this redefines a cabal + # command that gets rid of annoying "Writing: .....*.html" output + # when running cabal test. + shellHook = pre-commit.shellHook + '' + function cabal() { + if [ "$1" != "test" ]; then + command cabal "$@" + else + command cabal --test-option=--color=always "$@" | grep -vE --color=never "^Writing:.*html$" + fi + } + export -f cabal + ''; + }; }; - }; checks = { inherit pre-commit; }; - }); + } + ); nixConfig = { extra-trusted-substituters = [ diff --git a/package.yaml b/package.yaml index 65265092..d3199ffd 100644 --- a/package.yaml +++ b/package.yaml @@ -2,7 +2,7 @@ verbatim: cabal-version: 3.4 name: cooked-validators -version: 7.0.0 +version: 8.0.0 dependencies: - QuickCheck From 4ae6208713541ea598ced0600a898a3e251d12bc Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 12:40:07 +0100 Subject: [PATCH 2/9] example in README --- README.md | 102 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d227c11e..8c411742 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ The library is designed to: - make test scenarios more readable and maintainable, - facilitate adversarial testing and vulnerability discovery. +Importantly, `cooked-validators` is non-invasive: everything it automates can +also be done manually if needed, allowing users to retain full control over +transaction construction when desired. + ## Core features With `cooked-validators`, you can: @@ -44,14 +48,10 @@ to [UPLC](https://plutonomicon.github.io/plutonomicon/uplc), such as * specifying the expected number of outcomes in case branching occurred, * asserting exact error messages in case of failure, * ensuring a specific event was triggered during the run, - * checking the assets present at a given address. + * checking that some specific assets are present at a given address. ## How to integrate `cooked-validators` in a project -To use `cooked-validators`, you need -- [GHC](https://www.haskell.org/ghc/download_ghc_9_6_7.html) version 9.6.7 -- [Cabal](https://www.haskell.org/cabal) version 3.10 or later - 1. `cooked-validators` depends on [cardano-haskell-packages](https://github.com/input-output-hk/cardano-haskell-packages) to get cardano-related packages and on @@ -74,36 +74,76 @@ the `packages` stanza. (see [available releases](https://github.com/tweag/cooked-validators/releases)). +3. Each release of `cooked-validators` is pinned to a specific version of + [`cardano-api`](https://github.com/IntersectMBO/cardano-api) which in turn + pins the versions of all other Cardano-related dependencies (including + Plutus). Make sure your project relies on the same version. + ## Example -1. Make your project - [depend](https://cabal.readthedocs.io/en/stable/getting-started.html#adding-dependencies) - on `cooked-validators` and `plutus-script-utils` - -2. Enter a Cabal read-eval-print-loop (with `cabal repl`) - and create and validate a transaction which transfers 10 Ada - from wallet 1 to wallet 2: - ```haskell +This example shows how to create and validate a simple transaction that +transfers 10 Ada from wallet 1 to wallet 2, without manually handling fees or +balancing. + +1. Enter a Cabal read-eval-print-loop (with `cabal repl`) + +2. Import your required dependencies + ``` haskell > import Cooked > import qualified Plutus.Script.Utils.Value as Script - > printCooked . runMockChain . validateTxSkel $ - txSkelTemplate - { txSkelOuts = [wallet 2 `receives` Value (Script.ada 10)], - txSkelSigners = [wallet 1] - } - [...] - - UTxO state: - • pubkey wallet 1 - - Lovelace: 89_828_471 - - (×4) Lovelace: 100_000_000 - • pubkey wallet 2 - - Lovelace: 10_000_000 - - (×5) Lovelace: 100_000_000 - • pubkey wallet 3 - - (×5) Lovelace: 100_000_000 - • pubkey wallet 4 - - (×5) Lovelace: 100_000_000 - [...] + ``` + +3. Define a transaction which transfers 10 Ada from wallet 1 to wallet 2 + ``` haskell + let myTransaction = txSkelTemplate {txSkelOuts = [wallet 2 `receives` Value (Script.ada 10)], txSkelSignatories = txSkelSignatoriesFromList [wallet 1]} + ``` + +4. Send the transaction for validation, and request the printing of the run + ``` haskell + printCooked . runMockChain . validateTxSkel_ $ myTransaction + ``` + +5. Observe the log of the run, including all the adjustments made by + `cooked-validators`, the final mockchain state and returned value. + ```haskell + 📖 MockChain run log: + ⁍ New raw skeleton submitted to the adjustment pipeline: + - Validity interval: (-∞ , +∞) + - Signatories: + - wallet 1 [balancing] + - Outputs: + - Pays to pubkey wallet 2 + - Lovelace: 10_000_000 + ⁍ New adjusted skeleton submitted for validation: + - Validity interval: (-∞ , +∞) + - Signatories: + - wallet 1 [balancing] + - Inputs: + - Spends #4480b35!3 from pubkey wallet 1 + - Redeemer () + - Lovelace: 100_000_000 + - Outputs: + - Pays to pubkey wallet 2 + - Lovelace: 10_000_000 + - Pays to pubkey wallet 1 + - Lovelace: 89_828_383 + - Fee: Lovelace: 171_617 + - No collateral required + ⁍ New transaction successfully validated: + - Transaction id: #c095342 + - Number of new outputs: 2 + ✅ UTxO state: + • pubkey wallet 1 + - Lovelace: 89_828_383 + - (×3) Lovelace: 100_000_000 + • pubkey wallet 2 + - Lovelace: 10_000_000 + - (×4) Lovelace: 100_000_000 + • pubkey wallet 3 + - (×4) Lovelace: 100_000_000 + • pubkey wallet 4 + - (×4) Lovelace: 100_000_000 + 🟢 Returned value: () ``` ## Documentation From 884e77dd141d37eca7797e7970e5303767661a09 Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 12:53:39 +0100 Subject: [PATCH 3/9] finishing README --- README.md | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8c411742..30a305a0 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,12 @@ balancing. printCooked . runMockChain . validateTxSkel_ $ myTransaction ``` -5. Observe the log of the run, including all the adjustments made by - `cooked-validators`, the final mockchain state and returned value. +5. Observe the log of the run, including: + - The original skeleton, and its balanced counterpart + - The associated fee and collaterals + - The final mockchain state, with every wallet's assets (notice the 10 ADA + payment owned by wallet 2) + - The value returned by the run (here `()` as we used `validateTxSkel_`) ```haskell 📖 MockChain run log: ⁍ New raw skeleton submitted to the adjustment pipeline: @@ -166,6 +170,32 @@ balancing. - The [OPTICS](doc/OPTICS.md) file describes our usage of optics to navigate our data structures. +## Blog posts + +Some blog posts have been written on `cooked-validators`. As the library is +being updated, some code snippets there might find themselves outdated. However, +the core philosophy of `cooked-validators` remains, and the they offer very +useful insight on how to use the library. + +1. [An article](https://www.tweag.io/blog/2023-05-11-audit-smart-contract/) + which explains how we use `cooked-validators` to conduct smart contract + audits. + +2. [An + article](https://www.tweag.io/blog/2025-02-20-transaction-generation-automation-with-cooked-validators/) + which depicts how transaction skeleton are built in `cooked-validators` and + how the library builds comprehensive transactions from them. + +3. [An + article](https://www.tweag.io/blog/2022-01-26-property-based-testing-of-monadic-code/) + depicting the original idea to use temporal modalities to modify sequences of + transactions. + +4. [An + article](https://www.tweag.io/blog/2022-01-26-property-based-testing-of-monadic-code/) + depicting how linear temporal logics is used in `cooked-validators` to deploy + modifications on time. + ## Additional resources - We have a [repository](https://github.com/tweag/cooked-smart-contracts) of From 5d524d0457fbf80881f30766630622f5096286a7 Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 13:00:03 +0100 Subject: [PATCH 4/9] fixing some mistakes in the readme --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 30a305a0..53ad50f8 100644 --- a/README.md +++ b/README.md @@ -172,29 +172,29 @@ balancing. ## Blog posts -Some blog posts have been written on `cooked-validators`. As the library is -being updated, some code snippets there might find themselves outdated. However, -the core philosophy of `cooked-validators` remains, and the they offer very -useful insight on how to use the library. +Several blog posts have been written about `cooked-validators`. As the library +evolves, some code snippets in these posts may become outdated. However, the +core philosophy remains unchanged, and these articles still provide valuable +insight into how to use the library. 1. [An article](https://www.tweag.io/blog/2023-05-11-audit-smart-contract/) - which explains how we use `cooked-validators` to conduct smart contract - audits. + explaining how we use `cooked-validators` to conduct smart contract audits. 2. [An article](https://www.tweag.io/blog/2025-02-20-transaction-generation-automation-with-cooked-validators/) - which depicts how transaction skeleton are built in `cooked-validators` and - how the library builds comprehensive transactions from them. + describing how transaction skeletons are built in `cooked-validators` and how + the library constructs complete transactions from them. 3. [An article](https://www.tweag.io/blog/2022-01-26-property-based-testing-of-monadic-code/) - depicting the original idea to use temporal modalities to modify sequences of - transactions. + presenting the original idea of using temporal modalities to modify sequences + of transactions. -4. [An - article](https://www.tweag.io/blog/2022-01-26-property-based-testing-of-monadic-code/) - depicting how linear temporal logics is used in `cooked-validators` to deploy - modifications on time. + +4. [An article](https://www.tweag.io/blog/2022-10-14-ltl-attacks/) explaining + how [linear temporal + logic](https://en.wikipedia.org/wiki/Linear_temporal_logic) is used in + `cooked-validators` to deploy modifications over time. ## Additional resources From be4d83ab942a7252e733ac2c7e0c3a4716cfbd70 Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 13:04:15 +0100 Subject: [PATCH 5/9] hm --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53ad50f8..ede9a729 100644 --- a/README.md +++ b/README.md @@ -173,8 +173,8 @@ balancing. ## Blog posts Several blog posts have been written about `cooked-validators`. As the library -evolves, some code snippets in these posts may become outdated. However, the -core philosophy remains unchanged, and these articles still provide valuable +evolves, some code snippets in these posts may have become outdated. However, +the core philosophy remains unchanged, and these articles still provide valuable insight into how to use the library. 1. [An article](https://www.tweag.io/blog/2023-05-11-audit-smart-contract/) From 1e6b3a9d6973c001e578b0c6d23b65f3224d4e9d Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 15:03:09 +0100 Subject: [PATCH 6/9] reverting flake change and updating readme --- README.md | 21 ++++---- flake.lock | 22 ++++---- flake.nix | 154 +++++++++++++++++++++++++---------------------------- 3 files changed, 94 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index ede9a729..0d5cf13e 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,17 @@ Copyright Tweag I/O 2026 expressive off-chain code for Cardano smart contracts, with a primary focus on testing, auditing, and behavioral exploration. -It allows you to describe transactions at a high level (via transaction -skeletons) and automatically turn them into complete, valid transactions by -handling all mechanical aspects such UTxO selection, balancing, minimum-Ada -constraints, collaterals or fees. +It allows you to describe transactions at a high level (via what we call +transaction skeletons) and automatically turn them into complete, valid +transactions by handling all mechanical aspects such UTxO selection, balancing, +minimum-Ada constraints, collaterals or fees. The library is designed to: - drastically reduce off-chain boilerplate, - make test scenarios more readable and maintainable, - facilitate adversarial testing and vulnerability discovery. -Importantly, `cooked-validators` is non-invasive: everything it automates can +Importantly, `cooked-validators` is non-disruptive: everything it automates can also be done manually if needed, allowing users to retain full control over transaction construction when desired. @@ -37,18 +37,19 @@ to [UPLC](https://plutonomicon.github.io/plutonomicon/uplc), such as - Construct sequences of transactions in a clear, implementation-independent abstraction of the blockchain. - Run transaction sequences in an emulated blockchain. -- Apply tweaks to transactions just before submission, where tweaks are - modifications aware of the current blockchain state. +- Define modifications aware of the current blockchain state (tweaks), and apply + them to transactions just before submission. - Compose and deploy tweaks on sequences of transactions using idioms inspired by linear temporal logic. - Deploy automated attacks on existing transaction sequences, such as datum hijacking or double satisfaction attacks, to uncover vulnerabilities. -- Express expected outcomes of runs in a precise and declarative way, for - example by: +- Express expected outcomes on the result of running a trace in a precise and + declarative way, for example by: * specifying the expected number of outcomes in case branching occurred, * asserting exact error messages in case of failure, * ensuring a specific event was triggered during the run, - * checking that some specific assets are present at a given address. + * checking that some specific assets are present at a given address in the + final blockchain state. ## How to integrate `cooked-validators` in a project diff --git a/flake.lock b/flake.lock index 60d8f979..e5a6762f 100644 --- a/flake.lock +++ b/flake.lock @@ -3,15 +3,15 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1767039857, - "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", - "owner": "NixOS", + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", "repo": "flake-compat", - "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "type": "github" }, "original": { - "owner": "NixOS", + "owner": "edolstra", "repo": "flake-compat", "type": "github" } @@ -57,11 +57,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1768817753, - "narHash": "sha256-WaULpLu8QV07UNq3XUvvS/z/YHe34OoC32C////5EmE=", + "lastModified": 1766062740, + "narHash": "sha256-U9KVTNs7PvyND7gisDMiluOfwT5hvOlMH2LTYfAYpNk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "dda42211b8e9b4216aab429a24008215c6870b65", + "rev": "6dc87b326cef973e51ed3d2ffbdbe6240917a7be", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1767281941, - "narHash": "sha256-6MkqajPICgugsuZ92OMoQcgSHnD6sJHwk8AxvMcIgTE=", + "lastModified": 1765911976, + "narHash": "sha256-t3T/xm8zstHRLx+pIHxVpQTiySbKqcQbK+r+01XVKc0=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "f0927703b7b1c8d97511c4116eb9b4ec6645a0fa", + "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2d743bce..4fa9ba99 100644 --- a/flake.nix +++ b/flake.nix @@ -4,15 +4,8 @@ inputs.pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix"; inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs"; - outputs = - { - self, - nixpkgs, - flake-utils, - pre-commit-hooks, - }: - flake-utils.lib.eachDefaultSystem ( - system: + outputs = { self, nixpkgs, flake-utils, pre-commit-hooks }: + flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; hpkgs = pkgs.haskell.packages.ghc96; @@ -22,20 +15,21 @@ ## is due to a bug where older processors (>= 10 years) ## would not be supported. This should not change anything ## on newer machines. This could be revised in the future. - blst-portable = pkgs.blst.overrideAttrs ( - _: _: { - buildPhase = '' - runHook preBuild - ./build.sh -shared -D__BLST_PORTABLE__ ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows "flavour=mingw64"} - runHook postBuild - ''; - } - ); + blst-portable = pkgs.blst.overrideAttrs (_: _: { + buildPhase = '' + runHook preBuild + ./build.sh -shared -D__BLST_PORTABLE__ ${ + pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows + "flavour=mingw64" + } + runHook postBuild + ''; + }); pre-commit = pre-commit-hooks.lib.${system}.run { src = ./.; hooks = { - nixfmt.enable = true; + nixfmt-classic.enable = true; ormolu.enable = true; hpack.enable = true; }; @@ -51,79 +45,75 @@ ## for more information. }; }; - in - { - formatter = pkgs.nixfmt; + in { + formatter = pkgs.nixfmt-classic; - devShells = - let - ## The minimal dependency set to build the project with `cabal`. - buildInputs = [ - blst-portable - pkgs.pkg-config - pkgs.glibcLocales - pkgs.zlib - pkgs.libsodium - pkgs.secp256k1 - pkgs.lmdb - hpkgs.ghc - hpkgs.cabal-install - ]; + devShells = let + ## The minimal dependency set to build the project with `cabal`. + buildInputs = [ + blst-portable + pkgs.pkg-config + pkgs.glibcLocales + pkgs.zlib + pkgs.libsodium + pkgs.secp256k1 + pkgs.lmdb + hpkgs.ghc + hpkgs.cabal-install + ]; - ## Folders in which to find ".so" files - LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath [ - pkgs.xz - pkgs.zlib - pkgs.lmdb - pkgs.openssl_3_6 - pkgs.postgresql # For cardano-node-emulator - pkgs.openldap # For freer-extras‽ - pkgs.libsodium - pkgs.secp256k1 - pkgs.lmdb - blst-portable - ]; + ## Folders in which to find ".so" files + LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath [ + pkgs.xz + pkgs.zlib + pkgs.lmdb + pkgs.openssl_3_6 + pkgs.postgresql # For cardano-node-emulator + pkgs.openldap # For freer-extras‽ + pkgs.libsodium + pkgs.secp256k1 + pkgs.lmdb + blst-portable + ]; - LANG = "C.UTF-8"; + LANG = "C.UTF-8"; - in - { - ci = pkgs.mkShell { - inherit buildInputs; - inherit LD_LIBRARY_PATH; - inherit LANG; - }; + in { + ci = pkgs.mkShell { + inherit buildInputs; + inherit LD_LIBRARY_PATH; + inherit LANG; + }; - default = pkgs.mkShell { - buildInputs = buildInputs ++ [ - pkgs.hpack - pkgs.hlint - hpkgs.ormolu - hpkgs.haskell-language-server - ]; + default = pkgs.mkShell { + buildInputs = buildInputs ++ [ + pkgs.hpack + pkgs.hlint + hpkgs.ormolu + hpkgs.haskell-language-server + ]; - inherit LD_LIBRARY_PATH; - inherit LANG; + inherit LD_LIBRARY_PATH; + inherit LANG; - # In addition to the pre-commit hooks, this redefines a cabal - # command that gets rid of annoying "Writing: .....*.html" output - # when running cabal test. - shellHook = pre-commit.shellHook + '' - function cabal() { - if [ "$1" != "test" ]; then - command cabal "$@" - else - command cabal --test-option=--color=always "$@" | grep -vE --color=never "^Writing:.*html$" - fi - } - export -f cabal - ''; - }; + # In addition to the pre-commit hooks, this redefines a cabal + # command that gets rid of annoying "Writing: .....*.html" output + # when running cabal test. + shellHook = pre-commit.shellHook + '' + function cabal() { + if [ "$1" != "test" ]; then + command cabal "$@" + else + command cabal --test-option=--color=always "$@" | grep -vE --color=never "^Writing:.*html$" + fi + } + export -f cabal + ''; }; + }; checks = { inherit pre-commit; }; - } - ); + }); nixConfig = { extra-trusted-substituters = [ From 498d75143c78078f3a2362541fff283039eb6302 Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 15:20:08 +0100 Subject: [PATCH 7/9] nixfmt + non-opinionated --- README.md | 2 +- flake.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0d5cf13e..c11a5750 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The library is designed to: - make test scenarios more readable and maintainable, - facilitate adversarial testing and vulnerability discovery. -Importantly, `cooked-validators` is non-disruptive: everything it automates can +Importantly, `cooked-validators` is non-opinionated: everything it automates can also be done manually if needed, allowing users to retain full control over transaction construction when desired. diff --git a/flake.nix b/flake.nix index 4fa9ba99..308e1188 100644 --- a/flake.nix +++ b/flake.nix @@ -29,7 +29,7 @@ pre-commit = pre-commit-hooks.lib.${system}.run { src = ./.; hooks = { - nixfmt-classic.enable = true; + nixfmt.enable = true; ormolu.enable = true; hpack.enable = true; }; @@ -46,7 +46,7 @@ }; }; in { - formatter = pkgs.nixfmt-classic; + formatter = pkgs.nixfmt; devShells = let ## The minimal dependency set to build the project with `cabal`. From 4f6e73dfffbaee308386ffb39c0427f54600bbae Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 15:21:22 +0100 Subject: [PATCH 8/9] nixfmt --- flake.nix | 150 +++++++++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 70 deletions(-) diff --git a/flake.nix b/flake.nix index 308e1188..2d743bce 100644 --- a/flake.nix +++ b/flake.nix @@ -4,8 +4,15 @@ inputs.pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix"; inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs"; - outputs = { self, nixpkgs, flake-utils, pre-commit-hooks }: - flake-utils.lib.eachDefaultSystem (system: + outputs = + { + self, + nixpkgs, + flake-utils, + pre-commit-hooks, + }: + flake-utils.lib.eachDefaultSystem ( + system: let pkgs = nixpkgs.legacyPackages.${system}; hpkgs = pkgs.haskell.packages.ghc96; @@ -15,16 +22,15 @@ ## is due to a bug where older processors (>= 10 years) ## would not be supported. This should not change anything ## on newer machines. This could be revised in the future. - blst-portable = pkgs.blst.overrideAttrs (_: _: { - buildPhase = '' - runHook preBuild - ./build.sh -shared -D__BLST_PORTABLE__ ${ - pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows - "flavour=mingw64" - } - runHook postBuild - ''; - }); + blst-portable = pkgs.blst.overrideAttrs ( + _: _: { + buildPhase = '' + runHook preBuild + ./build.sh -shared -D__BLST_PORTABLE__ ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows "flavour=mingw64"} + runHook postBuild + ''; + } + ); pre-commit = pre-commit-hooks.lib.${system}.run { src = ./.; @@ -45,75 +51,79 @@ ## for more information. }; }; - in { + in + { formatter = pkgs.nixfmt; - devShells = let - ## The minimal dependency set to build the project with `cabal`. - buildInputs = [ - blst-portable - pkgs.pkg-config - pkgs.glibcLocales - pkgs.zlib - pkgs.libsodium - pkgs.secp256k1 - pkgs.lmdb - hpkgs.ghc - hpkgs.cabal-install - ]; + devShells = + let + ## The minimal dependency set to build the project with `cabal`. + buildInputs = [ + blst-portable + pkgs.pkg-config + pkgs.glibcLocales + pkgs.zlib + pkgs.libsodium + pkgs.secp256k1 + pkgs.lmdb + hpkgs.ghc + hpkgs.cabal-install + ]; - ## Folders in which to find ".so" files - LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath [ - pkgs.xz - pkgs.zlib - pkgs.lmdb - pkgs.openssl_3_6 - pkgs.postgresql # For cardano-node-emulator - pkgs.openldap # For freer-extras‽ - pkgs.libsodium - pkgs.secp256k1 - pkgs.lmdb - blst-portable - ]; + ## Folders in which to find ".so" files + LD_LIBRARY_PATH = pkgs.lib.strings.makeLibraryPath [ + pkgs.xz + pkgs.zlib + pkgs.lmdb + pkgs.openssl_3_6 + pkgs.postgresql # For cardano-node-emulator + pkgs.openldap # For freer-extras‽ + pkgs.libsodium + pkgs.secp256k1 + pkgs.lmdb + blst-portable + ]; - LANG = "C.UTF-8"; + LANG = "C.UTF-8"; - in { - ci = pkgs.mkShell { - inherit buildInputs; - inherit LD_LIBRARY_PATH; - inherit LANG; - }; + in + { + ci = pkgs.mkShell { + inherit buildInputs; + inherit LD_LIBRARY_PATH; + inherit LANG; + }; - default = pkgs.mkShell { - buildInputs = buildInputs ++ [ - pkgs.hpack - pkgs.hlint - hpkgs.ormolu - hpkgs.haskell-language-server - ]; + default = pkgs.mkShell { + buildInputs = buildInputs ++ [ + pkgs.hpack + pkgs.hlint + hpkgs.ormolu + hpkgs.haskell-language-server + ]; - inherit LD_LIBRARY_PATH; - inherit LANG; + inherit LD_LIBRARY_PATH; + inherit LANG; - # In addition to the pre-commit hooks, this redefines a cabal - # command that gets rid of annoying "Writing: .....*.html" output - # when running cabal test. - shellHook = pre-commit.shellHook + '' - function cabal() { - if [ "$1" != "test" ]; then - command cabal "$@" - else - command cabal --test-option=--color=always "$@" | grep -vE --color=never "^Writing:.*html$" - fi - } - export -f cabal - ''; + # In addition to the pre-commit hooks, this redefines a cabal + # command that gets rid of annoying "Writing: .....*.html" output + # when running cabal test. + shellHook = pre-commit.shellHook + '' + function cabal() { + if [ "$1" != "test" ]; then + command cabal "$@" + else + command cabal --test-option=--color=always "$@" | grep -vE --color=never "^Writing:.*html$" + fi + } + export -f cabal + ''; + }; }; - }; checks = { inherit pre-commit; }; - }); + } + ); nixConfig = { extra-trusted-substituters = [ From 7ea82dbbd6f0a803bc6da111911a49b45740a9b9 Mon Sep 17 00:00:00 2001 From: mmontin Date: Mon, 19 Jan 2026 15:40:42 +0100 Subject: [PATCH 9/9] hpack --- cooked-validators.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cooked-validators.cabal b/cooked-validators.cabal index fe1b1774..fd4ae74a 100644 --- a/cooked-validators.cabal +++ b/cooked-validators.cabal @@ -1,6 +1,6 @@ cabal-version: 3.4 --- This file has been generated from package.yaml by hpack version 0.38.3. +-- This file has been generated from package.yaml by hpack version 0.38.2. -- -- see: https://github.com/sol/hpack