Skip to content

Commit cffafd7

Browse files
authored
Merge pull request #6 from BlockstreamResearch/feature/polishing
Options covenant: conditional change outputs, dynamic input index
2 parents 3472704 + 9a01ddb commit cffafd7

8 files changed

Lines changed: 687 additions & 365 deletions

File tree

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,123 @@
11
## Simplicity Contracts
2+
3+
Workspace for prototyping and exercising Simplicity-based contracts on Liquid testnet. It includes:
4+
- A small CLI for building and broadcasting transactions
5+
- A contracts crate housing Simplicity sources and helpers (e.g., an Options covenant contract)
6+
- A high-level helper library to compile, run, and finalize Simplicity programs
7+
8+
## Workspace structure
9+
10+
- `crates/simplicityhl-core` — High-level helpers around Simplicity on Elements/Liquid
11+
- Address derivation for P2TR Simplicity programs (`create_p2tr_address`, `get_p2pk_address`)
12+
- Program compilation and execution (`load_program`, `run_program`), trackers, and logging
13+
- Transaction finalization helpers to attach Simplicity witnesses (`finalize_transaction`, `finalize_p2pk_transaction`)
14+
- Explorer utilities for Esplora broadcast/fetch with on-disk caching
15+
- Constants for Liquid testnet (policy asset, LBTC id, genesis hash)
16+
- Embedded `p2pk.simf` program
17+
18+
- `crates/contracts` — Contract templates and helpers
19+
- `options/` contains a Simplicity Options contract (`options.simf`), argument builders, and witness builders
20+
- `get_options_program`, `get_options_address`, and `finalize_options_funding_path_transaction`
21+
- Bincode-based encoding of argument structs (via `simplicityhl-core` encoding feature)
22+
23+
- `crates/cli` — Simplicity helper CLI (Liquid testnet)
24+
- `basic` commands: P2PK address derivation and simple LBTC/asset transfers
25+
- `options` commands: create/fund/exercise/settle/expire/cancel paths for the Options contract
26+
- Uses a local sled store at `.cache/store` for argument persistence
27+
28+
### Note
29+
30+
- Finalization and verification
31+
- `finalize_transaction` and `finalize_p2pk_transaction` verify the input UTXO’s script matches the program CMR+key, build an `ElementsEnv`, execute the program, and attach the Simplicity witness to the chosen input.
32+
33+
- Ephemeral key binding
34+
- `TaprootPubkeyGen` deterministically binds a program’s arguments to a public key and address without holding a private key. Its string form is `<seed_hex>:<xonly_pubkey>:<taproot_address>` and can be re-verified later with the same arguments.
35+
36+
## Expected behavior
37+
38+
- General
39+
- All transactions built here are explicit (unblinded). Fee outputs are explicit LBTC. The code targets Liquid testnet (`AddressParams::LIQUID_TESTNET`).
40+
- The CLI fetches UTXOs from the Liquid Testnet explorer and caches raw tx hex under `.cache/explorer/tx/`.
41+
- When `--broadcast` is provided, transactions are POSTed to Esplora and the txid is printed. Without it, raw hex is printed.
42+
43+
- Basic CLI (P2PK)
44+
- `basic address <index>` prints the derived X-only public key and its P2TR address.
45+
- `basic transfer-native` builds a 1-in/2-out LBTC spend with change + a separate fee output, then Schnorr-signs and optionally broadcasts.
46+
- `basic split-native` enforces that `first + second + fee == input value` for exact splits.
47+
- `basic transfer-asset` spends an ASSET UTXO and a separate LBTC fee UTXO, returning change for both and enforcing the fee UTXO is LBTC.
48+
49+
- Options contract
50+
- Creation: mints two reissuance tokens (option/grantor), persists entropies for later reissuance, derives/stores `OptionsArguments`, and prints the `TaprootPubkeyGen` string for the covenant instance.
51+
- Funding: reissues both tokens forward to the covenant address, deposits LBTC collateral, returns base assets as change, and attaches Simplicity witnesses for both token inputs.
52+
- Exercise (option-holder): burns option tokens, posts the settlement amount in target asset back to the covenant, and withdraws the proportional collateral to a P2PK recipient. Uses `fallback_locktime` and `Sequence::ENABLE_LOCKTIME_NO_RBF` where required by the covenant.
53+
- Settlement (grantor): burns grantor tokens against target asset held by the covenant, forwards settlement asset, and pays fees from a P2PK LBTC UTXO.
54+
- Expiry (grantor): after expiry, burns grantor tokens and withdraws the corresponding collateral to a P2PK recipient (fees deducted from collateral input).
55+
- Cancellation: burns both tokens and withdraws a portion of collateral to a P2PK recipient (fees deducted from collateral input).
56+
- The covenant expects specific output ordering and conditional change outputs; the CLI constructs outputs in that order.
57+
58+
## Getting started
59+
60+
Prerequisites
61+
- Rust (as per crate requirements; `simplicityhl-core` declares `rust-version = 1.90`)
62+
63+
Setup
64+
1. In `crates/cli`, create a `.env` file with a 32-byte hex seed:
65+
```
66+
SEED_HEX=000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
67+
```
68+
2. Build and view help:
69+
```
70+
cargo run -p cli -- --help
71+
```
72+
73+
Examples
74+
- Address derivation:
75+
```
76+
cargo run -p cli -- basic address 0
77+
```
78+
- Transfer LBTC (print hex or broadcast):
79+
```
80+
cargo run -p cli -- basic transfer-native \
81+
--utxo <txid>:<vout> \
82+
--to-address <tlq1...> \
83+
--send-sats 150000 \
84+
--fee-sats 500 \
85+
--account-index 0 \
86+
--broadcast
87+
```
88+
- Options import/export of encoded arguments:
89+
```
90+
cargo run -p cli -- options import --help
91+
cargo run -p cli -- options export --help
92+
```
93+
- Options flows (creation → funding → exercise/settlement/expiry/cancellation): see `crates/cli/README.md` for full command lines.
94+
95+
## Development tips
96+
97+
- Tests
98+
- Unit tests exist in `contracts` and `simplicityhl-core` (including program path tests). Run:
99+
```
100+
cargo test -p simplicityhl-core -p contracts
101+
```
102+
103+
- Debugging program execution
104+
- Use `RunnerLogLevel::{Debug,Trace}` and the provided trackers (`DefaultTracker`, `DebugTracker`) to observe `dbg!` values and jet traces during execution.
105+
- **Logs can be printed only if the program is successfully executed!**
106+
107+
- Encoding and persistence
108+
- Enable the `encoding` feature in `simplicityhl-core` to use the `Encodable` trait for bincode encoding/decoding of arguments. The CLI persists encoded options arguments in a local sled store under `.cache/store`.
109+
110+
- Adding a new contract
111+
1. Add a new `*.simf` under `crates/contracts/<your_contract>/source_simf/`.
112+
2. Create argument and witness builders mirroring `options/build_arguments.rs` and `options/build_witness.rs`.
113+
3. Expose helpers to derive the address and finalize transactions.
114+
4. Add CLI subcommands that construct outputs in the order your covenant expects, then attach the appropriate Simplicity witness(es).
115+
116+
- Performance and UX
117+
- Transactions are explicit; Addresses are constantly reused; privacy is not a goal here.
118+
119+
## Safety and network notes
120+
121+
- Liquid testnet only. Explicit transactions leak amounts/assets by design here.
122+
- Ensure UTXOs spent by the CLI belong to the derived P2TR address for the chosen `account-index`.
123+
- Always verify the printed addresses and parameters match your expectations before broadcasting.

crates/cli/README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,3 +282,110 @@ cargo run -p cli -- options cancellation-option \
282282
OutPoint format note:
283283

284284
- An OutPoint is specified as `<txid>:<vout>`, where `<txid>` is hex and `<vout>` is a non-negative integer index.
285+
286+
## Example run:
287+
288+
```bash
289+
cargo run -p cli -- options creation-option \
290+
--broadcast \
291+
--first-fee-utxo 4b9673c0034090120dee92122a87971b6b76b74e5a0c2787d0e2407c4fb774fb:1 \
292+
--second-fee-utxo 4b9673c0034090120dee92122a87971b6b76b74e5a0c2787d0e2407c4fb774fb:2 \
293+
--start-time 1760358546 \
294+
--expiry-time 1760358546 \
295+
--contract-size 20 \
296+
--asset-strike-price 2 \
297+
--collateral-amount 2000 \
298+
--target-asset-id-hex-be 38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5 \
299+
--account-index 0 \
300+
--fee-amount 100
301+
```
302+
303+
options_taproot_pubkey_gen: 1a9058141ebe163ff26739beb2f2c297e59aeb0983bd1696bb3b5dd18812baac:0270e34efde3af793343554a45be7c11b2b7289a0abf568295f909f81caa6fdedf:tex1pyj9x7gghxxtex90cxzlderjt0v69hm9zlz7ezzjmpzu4v3nwhgpq7pdnpa
304+
Broadcasted txid: https://liquid.network/testnet/tx/1b723210d29a7941aab47cbb6f2f08853fa08d32ed744bb384f4eaf5b905480e
305+
306+
-- Expiry test
307+
options_taproot_pubkey_gen: ca0367f594007e3b918b1d6390960a01a5f7704ee7d8902cbfa301cb276bb4a0:02e7ce0bbe949c9afe1671543bf8e49039f23bea800d3c4a89f9097b6ec7654889:tex1pxjm067n88g5xckhpqkss0cjntm3v27dky0qqenh8wpqqkr8mwxfqsag4uk
308+
Broadcasted txid: https://liquid.network/testnet/tx/d0d6d886386a19d5019d25a0eb7f0a19437996b85d70b688e1030f7d6eee8a36
309+
310+
-- Cancellation test
311+
options_taproot_pubkey_gen: a69b166def4cae06313f0791bd5d20d20d671e56cb6606b6fde261e6c3f17676:02c082825f70e6dcd1f5368e30cc290bf58127cddb3f4a0e5db20d8efd2ba7c504:tex1pr2eec37d0stuflmjlw62hrhr0uppw0jfdy8qnr5s2al3na3jwjrq8ans2x
312+
Broadcasted txid: https://liquid.network/testnet/tx/d97de05cd0d721fb1c4902eab84787a6c8cf245bcee4e3c18fa307d807d05ad9
313+
314+
```bash
315+
cargo run -p cli -- options funding-option \
316+
--broadcast \
317+
--option-asset-utxo d97de05cd0d721fb1c4902eab84787a6c8cf245bcee4e3c18fa307d807d05ad9:0 \
318+
--grantor-asset-utxo d97de05cd0d721fb1c4902eab84787a6c8cf245bcee4e3c18fa307d807d05ad9:1 \
319+
--collateral-and-fee-utxo d97de05cd0d721fb1c4902eab84787a6c8cf245bcee4e3c18fa307d807d05ad9:2 \
320+
--option-taproot-pubkey-gen a69b166def4cae06313f0791bd5d20d20d671e56cb6606b6fde261e6c3f17676:02c082825f70e6dcd1f5368e30cc290bf58127cddb3f4a0e5db20d8efd2ba7c504:tex1pr2eec37d0stuflmjlw62hrhr0uppw0jfdy8qnr5s2al3na3jwjrq8ans2x \
321+
--collateral-amount 2000 \
322+
--account-index 0 \
323+
--fee-amount 205
324+
```
325+
326+
Done: https://liquid.network/testnet/tx/24dbb9f54f8302eae4610257898c218ae96c9e72512fe887f03a693180e7f037
327+
Done (expiry test): https://liquid.network/testnet/tx/ad7670fb7d7c6538eb2f2478243e3fd8672aa689c87656dcd615e66d74905288
328+
Done (cancellation test): https://liquid.network/testnet/tx/f4d171ac050d177e46b3ca68b33e42394e594bda2cc908113fed80a8c57dd8d0
329+
330+
```bash
331+
cargo run -p cli -- options exercise-option \
332+
--broadcast \
333+
--collateral-utxo 6dc876cd4f41d7de588fecc88da9c5be02f3bfd16c402c8f7f233863d4cb5af3:0 \
334+
--option-asset-utxo 6dc876cd4f41d7de588fecc88da9c5be02f3bfd16c402c8f7f233863d4cb5af3:3 \
335+
--asset-utxo 6dc876cd4f41d7de588fecc88da9c5be02f3bfd16c402c8f7f233863d4cb5af3:4 \
336+
--fee-utxo 6dc876cd4f41d7de588fecc88da9c5be02f3bfd16c402c8f7f233863d4cb5af3:5 \
337+
--option-taproot-pubkey-gen 1a9058141ebe163ff26739beb2f2c297e59aeb0983bd1696bb3b5dd18812baac:0270e34efde3af793343554a45be7c11b2b7289a0abf568295f909f81caa6fdedf:tex1pyj9x7gghxxtex90cxzlderjt0v69hm9zlz7ezzjmpzu4v3nwhgpq7pdnpa \
338+
--amount-to-burn 75 \
339+
--fee-amount 160 \
340+
--account-index 0
341+
```
342+
343+
Done 1: https://liquid.network/testnet/tx/6dc876cd4f41d7de588fecc88da9c5be02f3bfd16c402c8f7f233863d4cb5af3
344+
Done 2: https://liquid.network/testnet/tx/ced2be5ee885df4b6230676e5d6b51c4e810d15f2324bf845d93d80ade7d29bf (full)
345+
346+
```bash
347+
cargo run -p cli -- options settlement-option \
348+
--broadcast \
349+
--target-asset-utxo 6dc876cd4f41d7de588fecc88da9c5be02f3bfd16c402c8f7f233863d4cb5af3:2 \
350+
--grantor-asset-utxo 91cb8282b61ac6fd2d4ed9973d8c3e6ddef31277a28022f68e30e8c743fd792b:2 \
351+
--fee-utxo 91cb8282b61ac6fd2d4ed9973d8c3e6ddef31277a28022f68e30e8c743fd792b:3 \
352+
--option-taproot-pubkey-gen 1a9058141ebe163ff26739beb2f2c297e59aeb0983bd1696bb3b5dd18812baac:0270e34efde3af793343554a45be7c11b2b7289a0abf568295f909f81caa6fdedf:tex1pyj9x7gghxxtex90cxzlderjt0v69hm9zlz7ezzjmpzu4v3nwhgpq7pdnpa \
353+
--grantor-token-amount-to-burn 25 \
354+
--fee-amount 150 \
355+
--account-index 0
356+
```
357+
358+
Done 1: https://liquid.network/testnet/tx/935820952db0590c168fd12da86d3a9729889d12871ee0a20a57ff4d061a5c73
359+
Done 2: https://liquid.network/testnet/tx/91cb8282b61ac6fd2d4ed9973d8c3e6ddef31277a28022f68e30e8c743fd792b (full 1)
360+
Done 3: https://liquid.network/testnet/tx/edcf54badff020ab84c4be83c8020e4b44dcab954ba337aa4a9beb1568d1842a (full 2)
361+
362+
```bash
363+
cargo run -p cli -- options expiry-option \
364+
--collateral-utxo a341cb1dbc256e2483ca9119852b0b4b3c2eb8f5d3bb9160785f4939733f3984:0 \
365+
--grantor-asset-utxo a341cb1dbc256e2483ca9119852b0b4b3c2eb8f5d3bb9160785f4939733f3984:3 \
366+
--fee-utxo a341cb1dbc256e2483ca9119852b0b4b3c2eb8f5d3bb9160785f4939733f3984:4 \
367+
--option-taproot-pubkey-gen ca0367f594007e3b918b1d6390960a01a5f7704ee7d8902cbfa301cb276bb4a0:02e7ce0bbe949c9afe1671543bf8e49039f23bea800d3c4a89f9097b6ec7654889:tex1pxjm067n88g5xckhpqkss0cjntm3v27dky0qqenh8wpqqkr8mwxfqsag4uk \
368+
--grantor-token-amount-to-burn 75 \
369+
--fee-amount 150 \
370+
--account-index 0 \
371+
--broadcast
372+
```
373+
374+
Done 1: https://liquid.network/testnet/tx/a341cb1dbc256e2483ca9119852b0b4b3c2eb8f5d3bb9160785f4939733f3984
375+
Done 2: https://liquid.network/testnet/tx/4b9673c0034090120dee92122a87971b6b76b74e5a0c2787d0e2407c4fb774fb (full)
376+
377+
```bash
378+
cargo run -p cli -- options cancellation-option \
379+
--collateral-utxo 2e622e2b235324d2a5731793deb0d384a346ccab8226ac848b25f710fbe8b6b4:0 \
380+
--option-asset-utxo 2e622e2b235324d2a5731793deb0d384a346ccab8226ac848b25f710fbe8b6b4:4 \
381+
--grantor-asset-utxo 2e622e2b235324d2a5731793deb0d384a346ccab8226ac848b25f710fbe8b6b4:5 \
382+
--fee-utxo 2e622e2b235324d2a5731793deb0d384a346ccab8226ac848b25f710fbe8b6b4:6 \
383+
--option-taproot-pubkey-gen a69b166def4cae06313f0791bd5d20d20d671e56cb6606b6fde261e6c3f17676:02c082825f70e6dcd1f5368e30cc290bf58127cddb3f4a0e5db20d8efd2ba7c504:tex1pr2eec37d0stuflmjlw62hrhr0uppw0jfdy8qnr5s2al3na3jwjrq8ans2x \
384+
--amount-to-burn 65 \
385+
--fee-amount 150 \
386+
--account-index 0 \
387+
--broadcast
388+
```
389+
390+
Done 1: https://liquid.network/testnet/tx/2e622e2b235324d2a5731793deb0d384a346ccab8226ac848b25f710fbe8b6b4
391+
Done 2: https://liquid.network/testnet/tx/e469665ea2bfe6ad3741f19f74a87abf4757caca09f1b08ec40e5bda0565eea7 (full)

0 commit comments

Comments
 (0)