Anatomy of a manifest
Before writing any recipes, let's look at the skeleton every manifest shares. A manifest is a single JSON document. At the top level it has an envelope of metadata fields followed by the data sections.
{
"manifest_version": "0.2.0",
"protocol": "p2pk-simplicity",
"description": "Pay-to-public-key using a Simplicity checksig program on Liquid.",
"chain": "liquid",
"utxo_types": { ... },
"contract_templates": { ... },
"actions": { ... }
}
The envelope
| Field | Required | Purpose |
|---|---|---|
manifest_version | yes | Version of the tx-manifest format itself. Current: "0.2.0". |
protocol | yes | Kebab-case protocol identifier, e.g. "simplicity-lending". |
description | no | Free-text summary of the whole protocol. |
chain | no | "bitcoin", "liquid"/"elements", or "cross-chain". Defaults to "elements". |
simplicity_hl | no | SimplicityHL toolchain settings. See below. |
Two authoring keys may appear on any object at any depth and carry no protocol
meaning: $comment, for prose a tool must ignore, and $schema, an editor hint
pointing at the JSON Schema. Both are stripped before a manifest is interpreted.
simplicity_hl — how the covenants are compiled
The whole block is optional, and so is every field in it. Written out with its defaults, it says exactly what omitting it says:
"simplicity_hl": {
"debug_symbols": false,
"unstable_features": []
}
| Field | Type | Default | Effect |
|---|---|---|---|
debug_symbols | boolean | false | Compile the .simf programs with debug symbols. Changes every covenant address. |
unstable_features | array of strings | [] | Allow gated SimplicityHL syntax. Never changes an address. |
debug_symbols
Compiles contracts with debug_symbols enabled. Note that this will change the CMR and addresses generated. In general this should not be used (or set to false), but is present to interact with contracts that are already deployed with this set to true.
unstable_features
The manifest form of simc -Z <name>. If you are using a contract that requires
unstable features, you can enable them here.
The data sections
Three sections describe the protocol itself. Most files carry two of them, and
none is required — a manifest with an empty actions map is still a manifest.
Each gets a chapter of its own; this table is the map.
| Section | Holds | Covered in |
|---|---|---|
utxo_types | The covenant addresses this protocol locks value to — one named entry per on-chain state, each pointing at a .simf program | Covenant UTXO types |
actions | One transaction recipe each: which UTXOs to consume, what to create, what witnesses satisfy them | Hello World, Outputs & destinations, Witnesses |
contract_templates | A typed contract: named fields plus the actions that operate on them, with one instance per deployment | Instance, state & constructors |
Two shapes, and when the second one arrives
A protocol with a single contract type can put its actions straight under
top-level actions, and give each one the params it needs. That is the whole
file — no templates, no instance. Every recipe up to
Witnesses is written this way.
contract_templates earns its place the moment a value has to outlive a single
transaction. A loan's collateral amount is chosen once, baked into a covenant
address, and then read back by four later actions; it cannot be a param, because
a param is gone when the transaction is built. Declaring it as a template
field stores it in the instance, where later actions reach it as
instance.NAME. That is the whole distinction, and
Parameters draws it out properly.
The two are not alternatives to choose between up front. A file may carry
top-level actions and contract_templates at once — the lending example does,
using standalone actions for setup work that belongs to no instance.
Read a real one. The fastest way to see how these fit together is
examples/p2pk/txmanifest.jsonin the wallet repository — the smallest complete manifest — and thenexamples/lending_v3, which uses every section at once.
For the exhaustive list of fields each section accepts, with types and defaults, see the manifest field reference.
What runs it
A manifest is declarative: it says what a transaction must look like, never how
to build one. Turning it into a signed transaction is a wallet's job —
tx-manifest-wallet resolves the params, finds the inputs, compiles the
covenants, builds and signs a PSET, dry-runs the Simplicity programs, and
broadcasts. Each recipe introduces the parts it needs, so there is nothing to
learn here up front; the
wallet implementation guide has the full
sequence for when you want it.
With the skeleton in hand, let's write our first contract.