@hazbase/simplicity 0.0.5 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +645 -148
  2. package/dist/cli.js +2125 -159
  3. package/dist/client/SimplicityClient.d.ts +64 -290
  4. package/dist/client/SimplicityClient.js +65 -23
  5. package/dist/core/executor.js +67 -92
  6. package/dist/core/outputBinding.d.ts +61 -0
  7. package/dist/core/outputBinding.js +552 -0
  8. package/dist/core/schnorr.d.ts +5 -0
  9. package/dist/core/schnorr.js +34 -0
  10. package/dist/core/types.d.ts +553 -1
  11. package/dist/docs/definitions/bond-anchor.simf +19 -0
  12. package/dist/docs/definitions/bond-definition.json +10 -0
  13. package/dist/docs/definitions/bond-descriptor-bound-settlement-machine.simf +144 -0
  14. package/dist/docs/definitions/bond-issuance-anchor.simf +26 -0
  15. package/dist/docs/definitions/bond-issuance-state-partial-redemption.json +18 -0
  16. package/dist/docs/definitions/bond-issuance-state-redeemed.json +18 -0
  17. package/dist/docs/definitions/bond-issuance-state.json +12 -0
  18. package/dist/docs/definitions/bond-redemption-state-machine.simf +118 -0
  19. package/dist/docs/definitions/bond-redemption-transition.simf +41 -0
  20. package/dist/docs/definitions/bond-script-bound-settlement-machine.simf +142 -0
  21. package/dist/docs/definitions/fund-capital-call-open.simf +82 -0
  22. package/dist/docs/definitions/fund-capital-call-refund-only.simf +33 -0
  23. package/dist/docs/definitions/fund-capital-call-state.json +11 -0
  24. package/dist/docs/definitions/fund-definition.json +8 -0
  25. package/dist/docs/definitions/fund-distribution-claim.simf +57 -0
  26. package/dist/docs/definitions/recursive-delay-direct-next.simf +60 -0
  27. package/dist/docs/definitions/recursive-delay-optional.simf +88 -0
  28. package/dist/docs/definitions/recursive-delay-required.simf +72 -0
  29. package/dist/docs/definitions/recursive-delay.simf +83 -0
  30. package/dist/docs/definitions/recursive-policy-transfer-machine.simf +65 -0
  31. package/dist/domain/bond.d.ts +8583 -721
  32. package/dist/domain/bond.js +1272 -31
  33. package/dist/domain/bondSettlementValidation.d.ts +2 -0
  34. package/dist/domain/bondSettlementValidation.js +28 -0
  35. package/dist/domain/bondValidation.d.ts +6 -0
  36. package/dist/domain/bondValidation.js +65 -3
  37. package/dist/domain/fund.d.ts +2069 -0
  38. package/dist/domain/fund.js +1384 -0
  39. package/dist/domain/fundValidation.d.ts +122 -0
  40. package/dist/domain/fundValidation.js +635 -0
  41. package/dist/domain/policies.d.ts +1051 -0
  42. package/dist/domain/policies.js +1605 -0
  43. package/dist/index.d.ts +5 -1
  44. package/dist/index.js +85 -21
  45. package/package.json +15 -2
package/README.md CHANGED
@@ -11,7 +11,411 @@ This SDK is designed to help Node developers get productive quickly, but it is s
11
11
 
12
12
  Consumer validation note:
13
13
  - The published npm package has been validated from a fresh external Node.js project using `npm install @hazbase/simplicity`.
14
- - Verified flows include preset-based contract execution, custom `.simf` execution, and relayer-backed gasless execution on `liquidtestnet`.
14
+ - Verified flows include preset-based contract execution, custom `.simf` execution, relayer-backed gasless execution, and LP-fund business-flow validation on `liquidtestnet`.
15
+
16
+ ## Recursive Policy SDK
17
+
18
+ The SDK now also exposes a generic `sdk.policies` domain for **parametric recursive covenants**.
19
+
20
+ That means you can model a UTXO as:
21
+ - a policy template definition,
22
+ - a concrete policy state for the current recipient,
23
+ - and a next constrained output that can re-apply the same `.simf` template to the next hop.
24
+
25
+ Initial reference implementation:
26
+ - `recursive-delay-required.simf`
27
+ - `recursive-delay-optional.simf`
28
+
29
+ Main entrypoints:
30
+ - `sdk.outputBinding.describeSupport()`
31
+ - `sdk.outputBinding.evaluateSupport(...)`
32
+ - `sdk.policies.describeTemplate(...)`
33
+ - `sdk.policies.validateTemplateParams(...)`
34
+ - `sdk.policies.issue(...)`
35
+ - `sdk.policies.prepareTransfer(...)`
36
+ - `sdk.policies.inspectTransfer(...)`
37
+ - `sdk.policies.executeTransfer(...)`
38
+ - `sdk.policies.verifyState(...)`
39
+ - `sdk.policies.verifyTransfer(...)`
40
+ - `sdk.policies.exportEvidence(...)`
41
+
42
+ Reference examples:
43
+ - [describe-policy-template.ts](./examples/describe-policy-template.ts)
44
+ - [custom-recursive-delay-required.manifest.json](./examples/custom-recursive-delay-required.manifest.json)
45
+ - [show-required-policy-transfer.ts](./examples/show-required-policy-transfer.ts)
46
+ - [show-optional-policy-transfer.ts](./examples/show-optional-policy-transfer.ts)
47
+ - [execute-required-policy-transfer.ts](./examples/execute-required-policy-transfer.ts)
48
+ - [execute-optional-policy-transfer.ts](./examples/execute-optional-policy-transfer.ts)
49
+
50
+ ### Policy Quickstart
51
+
52
+ The shortest happy path is:
53
+ 1. Describe the template and validate params
54
+ 2. Issue the first policy-aware UTXO
55
+ 3. Prepare, inspect, execute, and verify the next transfer
56
+
57
+ Required 1tx recursive hop:
58
+
59
+ ```ts
60
+ const templates = sdk.policies.listTemplates();
61
+ const bindingSupport = sdk.outputBinding.describeSupport();
62
+ const bindingEvaluation = sdk.outputBinding.evaluateSupport({
63
+ assetId: "bitcoin",
64
+ requestedBindingMode: "descriptor-bound",
65
+ outputForm: { amountForm: "confidential" },
66
+ });
67
+
68
+ const manifest = sdk.policies.describeTemplate({
69
+ templateId: "recursive-delay",
70
+ propagationMode: "required",
71
+ });
72
+
73
+ const params = sdk.policies.validateTemplateParams({
74
+ templateId: manifest.templateId,
75
+ propagationMode: "required",
76
+ params: { lockDistanceBlocks: 2 },
77
+ });
78
+
79
+ const externalManifest = await sdk.policies.loadTemplateManifest({
80
+ manifestPath: "./examples/custom-recursive-delay-required.manifest.json",
81
+ });
82
+
83
+ const issued = await sdk.policies.issue({
84
+ recipient: { mode: "policy", recipientXonly: currentRecipientXonly },
85
+ template: { templateId: "recursive-delay", value: { policyTemplateId: "recursive-delay" } },
86
+ params,
87
+ amountSat: 6000,
88
+ assetId: "bitcoin",
89
+ propagationMode: "required",
90
+ });
91
+
92
+ const prepared = await sdk.policies.prepareTransfer({
93
+ currentArtifact: issued.compiled.artifact,
94
+ template: { templateId: "recursive-delay", value: { policyTemplateId: "recursive-delay" } },
95
+ currentStateValue: issued.state,
96
+ nextReceiver: { mode: "policy", recipientXonly: nextRecipientXonly },
97
+ nextAmountSat: 6000,
98
+ nextParams: { lockDistanceBlocks: 2 },
99
+ outputBindingMode: "descriptor-bound",
100
+ });
101
+ ```
102
+
103
+ `sdk.outputBinding.describeSupport()` is the public support matrix for generalized binding. It tells you:
104
+ - which output forms can be auto-derived today,
105
+ - when manual `nextOutputHash` is still allowed,
106
+ - when `descriptor-bound` falls back to `script-bound`,
107
+ - and which runtime paths are validated locally vs on testnet.
108
+
109
+ `sdk.outputBinding.evaluateSupport(...)` is the quick deterministic answer for a specific scenario. It tells you:
110
+ - the requested binding mode,
111
+ - the resolved binding mode,
112
+ - the reason code,
113
+ - which unsupported features are blocking auto-derive,
114
+ - and whether the manual-hash path would keep `descriptor-bound` available.
115
+
116
+ If you want the `optional` branch instead, swap:
117
+ - `propagationMode: "optional"`
118
+ - `nextReceiver: { mode: "plain", address: ... }` for plain exit, or keep `mode: "policy"` for the recursive branch
119
+
120
+ The matching CLI flow is:
121
+ - `policy list-templates`
122
+ - `binding describe-support`
123
+ - `binding evaluate-support`
124
+ - `policy describe-template`
125
+ - `policy validate-template-params`
126
+ - `policy issue`
127
+ - `policy build-output-descriptor`
128
+ - `policy prepare-transfer`
129
+ - `policy inspect-transfer`
130
+ - `policy execute-transfer`
131
+ - `policy verify-state`
132
+ - `policy verify-transfer`
133
+ - `policy export-evidence`
134
+
135
+ For a testnet runtime example that spends an already-funded current policy UTXO, see:
136
+ - [execute-required-policy-transfer.ts](./examples/execute-required-policy-transfer.ts)
137
+ - [execute-optional-policy-transfer.ts](./examples/execute-optional-policy-transfer.ts)
138
+
139
+ The intended model is:
140
+ - `propagationMode: "required"`: next hop must remain policy-aware
141
+ - `propagationMode: "optional"`: next hop may remain policy-aware or exit to a plain address
142
+ - `propagationMode: "none"`: the policy ends at this hop
143
+
144
+ In `required` mode, the current state uses a **1tx direct hop**. The contract checks the current recipient, the relative timelock, the fee output shape, and the next constrained output script hash in the same spend.
145
+ In `optional` mode, the same current state can either:
146
+ - exit to a plain address, or
147
+ - bind the next constrained output in the same transaction
148
+ and the verification report marks the recursive branch as `conditional-hop`.
149
+
150
+ Current policy enforcement labels:
151
+ - `direct-hop`: `required` 1tx current -> next constrained output
152
+ - `conditional-hop`: `optional` mode when the recursive branch is chosen
153
+ - `sdk-path`: plain exit / no recursive enforcement
154
+
155
+ If a caller can supply `nextOutputHash`, both recursive policy templates can also take the stronger `descriptor-bound` path and compare `output_hash(0)` at runtime. In that case the amount becomes runtime-bound together with the rest of the output descriptor.
156
+ To make that path easier to use from the public policy API, the SDK now also exposes `sdk.policies.buildOutputDescriptor(...)` and the CLI command `policy build-output-descriptor`. These help derive the next constrained output address, script hash, and canonical descriptor summary before the transfer call.
157
+ The public binding paths are now:
158
+ - `explicit-v1`: `buildOutputDescriptor(...)` auto-derives `nextOutputHash` from high-level inputs when the asset is supplied as `bitcoin` or as a 64-character asset id
159
+ - `raw-output-v1`: advanced callers pass `assetBytesHex`, `amountBytesHex`, `nonceBytesHex`, plus either `scriptPubKeyHex` or `scriptPubKeyHashHex`, and either `rangeProofHex` or `rangeProofHashHex`, and the SDK derives `output_hash(0)` deterministically
160
+ - `manual-hash`: callers supply `nextOutputHash` directly and keep `descriptor-bound` even when auto-derive is unavailable or intentionally bypassed
161
+ - unsupported: the SDK falls back to `script-bound` and records the reason explicitly
162
+ Advanced callers can also pass output-form hints (`assetForm`, `amountForm`, `nonceForm`, `rangeProofForm`) to make confidential/generalized shapes explicit in the descriptor metadata.
163
+ Elements excludes surjection proofs from `output_hash(0)`, so the current generalized binding surface does not require `surjectionProofHex`.
164
+ If that auto-derivation is not available, the SDK now falls back to `script-bound` and records the fallback reason in the verification report instead of silently pretending the stronger mode succeeded.
165
+ The descriptor build result, transfer verification report, and evidence bundle now all carry the same derivation metadata:
166
+ - `supportedForm`
167
+ - `reasonCode`
168
+ - `autoDerived`
169
+ - `fallbackReason`
170
+ - `bindingInputs`
171
+
172
+ The policy verification and evidence JSON shapes are now versioned:
173
+ - `PolicyVerificationReport.schemaVersion = "policy-verification-report/v1"`
174
+ - `PolicyEvidenceBundle.schemaVersion = "policy-evidence-bundle/v1"`
175
+ and built-in/external template manifests use:
176
+ - `PolicyTemplateManifest.manifestVersion = "policy-template-manifest/v1"`
177
+
178
+ For relative timelocks, the public policy flow now also derives the contract input sequence from `lockDistanceBlocks`, so `check_lock_distance(...)` can be exercised on testnet without dropping back to the default spend sequence.
179
+
180
+ The public verification report now uses the same trust vocabulary across policy flows:
181
+ - `committed`
182
+ - `runtimeBound`
183
+ - `sdkVerified`
184
+
185
+ When an output binding is present, the report can also include:
186
+ - `supportedForm`
187
+ - `reasonCode`
188
+ - `nextOutputHash`
189
+ - `autoDerived`
190
+ - `fallbackReason`
191
+ - `bindingInputs`
192
+
193
+ This is intentionally explicit about current scope:
194
+ - `explicit-v1`:
195
+ - explicit asset
196
+ - explicit amount
197
+ - null nonce
198
+ - empty range proof
199
+ - asset input as `bitcoin` or a 64-character asset id
200
+ - `raw-output-v1`:
201
+ - caller provides raw output field bytes
202
+ - SDK derives `output_hash(0)` from those bytes deterministically
203
+ - `manual-hash`:
204
+ - caller provides `nextOutputHash` directly
205
+ - not yet treated as a default path:
206
+ - wallet/RPC-driven confidential output reconstruction
207
+
208
+ For the current runtime validation scope and timelock test-environment caveats, see [docs/design/recursive-policy-runtime-validation.md](./docs/design/recursive-policy-runtime-validation.md).
209
+ Reproducible policy confidence commands:
210
+ - `npm run e2e:policy-local`
211
+ - `POLICY_OUTPUT_BINDING_MODE=script-bound npm run e2e:policy-testnet`
212
+ - `POLICY_OUTPUT_BINDING_MODE=descriptor-bound npm run e2e:policy-testnet`
213
+ - `npm run e2e:policy-consumer`
214
+
215
+ ## LP Fund Settlement Layer
216
+
217
+ The SDK now also exposes `sdk.funds` as a dedicated business layer for **LP fund settlement on Liquid**.
218
+
219
+ Security-first vNext model:
220
+ - capital calls are explicit `open -> rollover -> refund-only`
221
+ - manager claim exists only on the `open` artifact
222
+ - LP refund exists only on the `refund-only` artifact
223
+ - `LPPositionReceipt` is an off-chain canonical document wrapped in a manager-attested envelope
224
+ - closing accepts only the latest attested receipt envelope
225
+
226
+ This layer is intentionally narrower than a full fund-admin system. It focuses on:
227
+ - capital call funding / manager claim / rollover / LP refund
228
+ - signed `LPPositionReceiptEnvelope` generation and reconciliation
229
+ - later one-shot distribution claim contracts
230
+ - finality / close-out evidence
231
+
232
+ It does **not** introduce `sdk.rwas`. The public architecture remains:
233
+ - `sdk.outputBinding`: shared binding support / fallback contract
234
+ - `sdk.policies`: generic recursive covenant engine
235
+ - `sdk.bonds`: credit / bond business layer
236
+ - `sdk.funds`: LP fund settlement business layer
237
+
238
+ Main entrypoints:
239
+ - `sdk.funds.define(...)`
240
+ - `sdk.funds.verify(...)`
241
+ - `sdk.funds.load(...)`
242
+ - `sdk.funds.prepareCapitalCall(...)`
243
+ - `sdk.funds.inspectCapitalCallClaim(...)`
244
+ - `sdk.funds.executeCapitalCallClaim(...)`
245
+ - `sdk.funds.inspectCapitalCallRollover(...)`
246
+ - `sdk.funds.executeCapitalCallRollover(...)`
247
+ - `sdk.funds.inspectCapitalCallRefund(...)`
248
+ - `sdk.funds.executeCapitalCallRefund(...)`
249
+ - `sdk.funds.verifyCapitalCall(...)`
250
+ - `sdk.funds.signPositionReceipt(...)`
251
+ - `sdk.funds.verifyPositionReceipt(...)`
252
+ - `sdk.funds.prepareDistribution(...)`
253
+ - `sdk.funds.inspectDistributionClaim(...)`
254
+ - `sdk.funds.executeDistributionClaim(...)`
255
+ - `sdk.funds.verifyDistribution(...)`
256
+ - `sdk.funds.reconcilePosition(...)`
257
+ - `sdk.funds.prepareClosing(...)`
258
+ - `sdk.funds.verifyClosing(...)`
259
+ - `sdk.funds.exportEvidence(...)`
260
+ - `sdk.funds.exportFinalityPayload(...)`
261
+
262
+ Reference examples:
263
+ - [show-fund-claim-close-flow.ts](./examples/show-fund-claim-close-flow.ts)
264
+ - [show-fund-refund-flow.ts](./examples/show-fund-refund-flow.ts)
265
+ - [fund-definition.json](./docs/definitions/fund-definition.json)
266
+ - [fund-capital-call-state.json](./docs/definitions/fund-capital-call-state.json)
267
+
268
+ ### Fund Quickstart
269
+
270
+ The intended split for LP fund workflows is:
271
+
272
+ - off-chain:
273
+ - KYC/AML
274
+ - subscription docs
275
+ - capital account / waterfall / NAV
276
+ - allocation calculation
277
+ - on-chain SDK:
278
+ - capital call funding / claim / rollover / refund
279
+ - distribution payout
280
+ - finality / close-out evidence
281
+
282
+ Minimal flow:
283
+
284
+ ```ts
285
+ const capitalCall = await sdk.funds.prepareCapitalCall({
286
+ definitionPath: "./docs/definitions/fund-definition.json",
287
+ capitalCallPath: "./docs/definitions/fund-capital-call-state.json",
288
+ });
289
+
290
+ const initialReceipt = buildLPPositionReceipt({
291
+ positionId: "POS-001",
292
+ capitalCall: capitalCall.capitalCallValue,
293
+ effectiveAt: "2026-03-18T00:00:00Z",
294
+ });
295
+
296
+ const signedInitialReceipt = await sdk.funds.signPositionReceipt({
297
+ definitionPath: "./docs/definitions/fund-definition.json",
298
+ positionReceiptValue: initialReceipt,
299
+ signer: { type: "schnorrPrivkeyHex", privkeyHex: managerPrivkeyHex },
300
+ signedAt: "2026-03-18T00:00:00Z",
301
+ });
302
+
303
+ const firstDistribution = await sdk.funds.prepareDistribution({
304
+ definitionPath: "./docs/definitions/fund-definition.json",
305
+ positionReceiptValue: signedInitialReceipt.positionReceiptEnvelope,
306
+ distributionId: "DIST-001",
307
+ assetId: capitalCall.capitalCallValue.currencyAssetId,
308
+ amountSat: 2000,
309
+ approvedAt: "2027-03-18T00:00:00Z",
310
+ });
311
+
312
+ const afterFirst = await sdk.funds.reconcilePosition({
313
+ definitionPath: "./docs/definitions/fund-definition.json",
314
+ positionReceiptValue: signedInitialReceipt.positionReceiptEnvelope,
315
+ distributionValue: firstDistribution.distributionValue,
316
+ signer: { type: "schnorrPrivkeyHex", privkeyHex: managerPrivkeyHex },
317
+ signedAt: "2027-03-18T00:00:00Z",
318
+ });
319
+
320
+ const secondDistribution = await sdk.funds.prepareDistribution({
321
+ definitionPath: "./docs/definitions/fund-definition.json",
322
+ positionReceiptValue: afterFirst.reconciledReceiptEnvelope,
323
+ distributionId: "DIST-002",
324
+ assetId: capitalCall.capitalCallValue.currencyAssetId,
325
+ amountSat: initialReceipt.fundedAmount - 2000,
326
+ approvedAt: "2028-03-18T00:00:00Z",
327
+ });
328
+
329
+ const afterSecond = await sdk.funds.reconcilePosition({
330
+ definitionPath: "./docs/definitions/fund-definition.json",
331
+ positionReceiptValue: afterFirst.reconciledReceiptEnvelope,
332
+ distributionValue: secondDistribution.distributionValue,
333
+ signer: { type: "schnorrPrivkeyHex", privkeyHex: managerPrivkeyHex },
334
+ signedAt: "2028-03-18T00:00:00Z",
335
+ });
336
+
337
+ const closing = await sdk.funds.prepareClosing({
338
+ definitionPath: "./docs/definitions/fund-definition.json",
339
+ positionReceiptValue: afterSecond.reconciledReceiptEnvelope,
340
+ closingId: "CLOSE-001",
341
+ finalDistributionHashes: [
342
+ firstDistribution.distributionSummary.hash,
343
+ secondDistribution.distributionSummary.hash,
344
+ ],
345
+ closedAt: "2029-03-18T00:00:00Z",
346
+ });
347
+ ```
348
+
349
+ The split examples are:
350
+ - `show-fund-claim-close-flow.ts`: receipt envelope -> two distributions -> manager-attested reconciliation -> closing/finality
351
+ - `show-fund-refund-flow.ts`: open capital call -> rollover -> refund-only evidence/finality
352
+
353
+ The matching CLI flow is:
354
+ - `fund define`
355
+ - `fund verify`
356
+ - `fund prepare-capital-call`
357
+ - `fund inspect-capital-call-claim`
358
+ - `fund execute-capital-call-claim`
359
+ - `fund inspect-capital-call-rollover`
360
+ - `fund execute-capital-call-rollover`
361
+ - `fund inspect-capital-call-refund`
362
+ - `fund execute-capital-call-refund`
363
+ - `fund verify-capital-call`
364
+ - `fund sign-position-receipt`
365
+ - `fund verify-position-receipt`
366
+ - `fund prepare-distribution`
367
+ - `fund inspect-distribution-claim`
368
+ - `fund execute-distribution-claim`
369
+ - `fund verify-distribution`
370
+ - `fund reconcile-position`
371
+ - `fund prepare-closing`
372
+ - `fund verify-closing`
373
+ - `fund export-evidence`
374
+ - `fund export-finality-payload`
375
+
376
+ Reproducible fund confidence commands:
377
+ - `npm run e2e:fund-local`
378
+ - `npm run e2e:fund-consumer`
379
+ - `FUND_OUTPUT_BINDING_MODE=script-bound npm run e2e:fund-testnet`
380
+ - `FUND_OUTPUT_BINDING_MODE=descriptor-bound npm run e2e:fund-testnet`
381
+ - `FUND_FLOW_MODE=refund FUND_OUTPUT_BINDING_MODE=script-bound npm run e2e:fund-testnet`
382
+ - `FUND_OUTPUT_BINDING_MODE=script-bound FUND_DISTRIBUTION_AMOUNTS_SAT=2000,4000 FUND_DISTRIBUTION_IDS=DIST-...-1,DIST-...-2 FUND_APPROVED_ATS=2027-03-18T00:00:00Z,2028-03-18T00:00:00Z npm run e2e:fund-testnet`
383
+ - `FUND_OUTPUT_BINDING_MODE=descriptor-bound FUND_DISTRIBUTION_AMOUNTS_SAT=2000,4000 FUND_DISTRIBUTION_IDS=DIST-...-1,DIST-...-2 FUND_APPROVED_ATS=2027-03-18T00:00:00Z,2028-03-18T00:00:00Z npm run e2e:fund-testnet`
384
+
385
+ Security notes for `sdk.funds`:
386
+ - on-chain enforced:
387
+ - `open` capital call allows manager claim only
388
+ - `refund-only` capital call allows LP refund only
389
+ - cutoff height is committed into the `open` artifact
390
+ - output binding uses the shared `script-bound` / `descriptor-bound` / `raw-output-v1` engine
391
+ - off-chain attested:
392
+ - `LPPositionReceiptEnvelope`
393
+ - manager attestation over receipt hash and sequence
394
+ - operationally enforced:
395
+ - watcher/keeper monitors `open` capital calls through `claimCutoffHeight`
396
+ - watcher/keeper submits rollover after cutoff
397
+ - LP refund becomes operationally available only after rollover confirmation
398
+
399
+ Latest fund testnet reruns:
400
+
401
+ | Flow | Funding txid | Main execution txid(s) | Closing / receipt | Rerun command |
402
+ | --- | --- | --- | --- | --- |
403
+ | `script-bound` claim-close | `a488a5c6e7c56ecca8d5860bf495590d38cfe8087f678f5664241b8eb90396de` | claim `43974a18c048f67f3399b614ea476ffb87c4622d8083636d1aeacbb51747d94d`; distributions `90fb3abdb000d9f66a18b1e2061fa06b56a51fe64513d358c47cc992c374e209`, `0644820b7fee4c11a9a66dbd1a14733ed2420435449717f4895d589f55b05b30` | receipt `f1f294c0f33405f31abbdd8a3a258e57c614bd381b61a7fba2ae420a35e77c70`; closing `19dfd60dfe04cbe1f145a2ab112ef5cf30a087e084837fa7bcce3ed80df72a2a` | `FUND_OUTPUT_BINDING_MODE=script-bound npm run e2e:fund-testnet` |
404
+ | `descriptor-bound` claim-close | `201b66c3843b9999703b08d242c547ca1d1f35619ca99e916d93e4ed70338bc6` | claim `c27621a27cb3b99b4d960cfa4be98de925beed7c3a7bd799fd3f88a3cb680762`; distributions `d4066986e90a9faa000032198307955583e318c0afd09d98691db7b07dc1b022`, `bbfe830790ef5a86a5595d0dccdd2a344efc7d3eebe7a597be1f2a5c2330dabb` | receipt `05b3e4b2c33518b22bd28939cef36972e7fe0c7273b24a6867fba40a0e374fce`; closing `b1ff75e989628130ec56e753f7bc48cc0648b82272c90dfee03f7582879835dd` | `FUND_OUTPUT_BINDING_MODE=descriptor-bound npm run e2e:fund-testnet` |
405
+ | `script-bound` refund | `3adf9025c4656d099752f2e5f43738495fbad712177b75f9330c05273eff12ff` | rollover `8b1224e808ad9824d7bf85924a07d62c75c038987a4163b2e450c455b962ed9d`; refund `6be225448ff062e1f2e8992cf3319601098b7b19edb0ea27823487e9a881f415` | refund-only settlement | `FUND_FLOW_MODE=refund FUND_OUTPUT_BINDING_MODE=script-bound npm run e2e:fund-testnet` |
406
+
407
+ Current runtime truth for claim-close / refund commands, latest txids, and rerun guidance lives in:
408
+ - [docs/design/fund-runtime-validation.md](./docs/design/fund-runtime-validation.md)
409
+
410
+ Latest Bond testnet reruns:
411
+
412
+ | Mode | Funding txid | Execution txid | Rerun command |
413
+ | --- | --- | --- | --- |
414
+ | `script-bound` | `1c982864ef6c83da4eb7f8018edc4cbdff439db7c6366984b3f85ad4937e2c4f` | `d659c4bdce6b32650ff58ac37ccaa55209a9f04d5dc4595f956fad034089f580` | `BOND_OUTPUT_BINDING_MODE=script-bound npm run e2e:bond-testnet` |
415
+ | `descriptor-bound` | `72d0015b51a74c3cc81f7abb74a4f6f894c7f7bbd1e83647939459d7b40e504f` | `85e0830a7b2ba33ca37d5f11bd981938418fc472e98657095680ada71387974c` | `BOND_OUTPUT_BINDING_MODE=descriptor-bound npm run e2e:bond-testnet` |
416
+
417
+ For current fund runtime scope and caveats, see:
418
+ - [docs/design/fund-runtime-validation.md](./docs/design/fund-runtime-validation.md)
15
419
 
16
420
  ## Validated Scenarios
17
421
 
@@ -24,6 +428,7 @@ The published package has been exercised from a blank external consumer project.
24
428
  | Preset flow (`p2pkLockHeight`) | Success | compile -> fund -> inspect -> execute(`broadcast=true`) |
25
429
  | Custom `.simf` flow | Success | `compileFromFile(...)` -> fund -> inspect -> execute(`broadcast=true`) |
26
430
  | Relayer-backed gasless flow | Success | `executeGasless(...)` succeeded from the external project |
431
+ | LP fund business flow | Success | packaged `sdk.funds` consumer smoke covers capital call, distribution, and finality |
27
432
 
28
433
  ## Who This Is For
29
434
 
@@ -136,210 +541,289 @@ For a bond-oriented walkthrough, see [docs/definitions/README.md](./docs/definit
136
541
 
137
542
  ## Trusted Issuance State JSON
138
543
 
139
- The same hash-anchor model now also applies to issuance state documents such as a bond issuance record.
140
-
141
- This is useful when you want to say not only:
544
+ The same hash-anchor model also applies to issuance state documents such as a bond issuance record.
142
545
 
546
+ This lets us say not only:
143
547
  - "these are the bond terms,"
144
548
 
145
549
  but also:
146
-
147
550
  - "this bond was issued in this amount, with this outstanding principal, under this controller."
148
551
 
149
- The SDK now supports:
150
-
552
+ The SDK supports:
151
553
  - loading and hashing a state JSON with `sdk.loadStateDocument(...)`,
152
554
  - storing its hash in the artifact,
153
555
  - committing `STATE_HASH` into custom `.simf` contract logic,
154
556
  - verifying later that the issuance state JSON still matches the compiled contract.
155
557
 
156
- For Bond issuance, the recommended shape is:
157
-
158
- ```json
159
- {
160
- "issuanceId": "BOND-2026-001-ISSUE-1",
161
- "bondId": "BOND-2026-001",
162
- "issuerEntityId": "hazbase-treasury",
163
- "issuedPrincipal": 1000000,
164
- "outstandingPrincipal": 1000000,
165
- "redeemedPrincipal": 0,
166
- "currencyAssetId": "bitcoin",
167
- "controllerXonly": "<xonly>",
168
- "issuedAt": "2026-03-10T00:00:00Z",
169
- "status": "ISSUED"
170
- }
171
- ```
172
-
173
- To move from an issued bond into a redemption state, the SDK now also supports a minimal state transition model:
558
+ The recommended Bond issuance shape still captures:
559
+ - `issuanceId`
560
+ - `bondId`
561
+ - `issuedPrincipal`
562
+ - `outstandingPrincipal`
563
+ - `redeemedPrincipal`
564
+ - `currencyAssetId`
565
+ - `controllerXonly`
566
+ - `issuedAt`
567
+ - `status`
568
+
569
+ ## Public Architecture
570
+
571
+ The SDK is now organized around four public layers:
572
+ - `sdk.outputBinding`: cross-domain output-binding support matrix and fallback behavior
573
+ - `sdk.policies`: generic recursive covenant / transfer engine
574
+ - `sdk.bonds`: Bond business layer built on Policy Core primitives and shared output binding
575
+ - `sdk.funds`: LP fund settlement business layer for capital calls, distributions, closing, and finality
576
+
577
+ This means:
578
+ - use `sdk.policies` when you want a generic constrained-transfer engine,
579
+ - use `sdk.bonds` when you want bond definition / issuance / redemption / settlement / closing / evidence semantics,
580
+ - use `sdk.funds` when you want LP capital call / distribution / closing semantics,
581
+ - use `sdk.outputBinding.describeSupport()` when you want the canonical explanation of supported forms, manual hash paths, and fallback behavior,
582
+ - use `sdk.outputBinding.evaluateSupport(...)` when you want the deterministic answer for one concrete output-form scenario.
583
+
584
+ ## Bond Domain Layer
585
+
586
+ `sdk.bonds` is now intentionally a **thin business facade**.
587
+
588
+ Its public responsibility is:
589
+ - bond definition / issuance / settlement / closing schema and invariant handling,
590
+ - business event orchestration,
591
+ - audit / evidence / finality payload export.
592
+
593
+ Public Bond API:
594
+ - `sdk.bonds.define(...)`
595
+ - `sdk.bonds.verify(...)`
596
+ - `sdk.bonds.load(...)`
597
+ - `sdk.bonds.issue(...)`
598
+ - `sdk.bonds.prepareRedemption(...)`
599
+ - `sdk.bonds.inspectRedemption(...)`
600
+ - `sdk.bonds.executeRedemption(...)`
601
+ - `sdk.bonds.verifyRedemption(...)`
602
+ - `sdk.bonds.buildSettlement(...)`
603
+ - `sdk.bonds.verifySettlement(...)`
604
+ - `sdk.bonds.prepareClosing(...)`
605
+ - `sdk.bonds.inspectClosing(...)`
606
+ - `sdk.bonds.executeClosing(...)`
607
+ - `sdk.bonds.verifyClosing(...)`
608
+ - `sdk.bonds.exportEvidence(...)`
609
+ - `sdk.bonds.exportFinalityPayload(...)`
610
+
611
+ What is no longer part of the public Bond surface:
612
+ - machine / rollover / state-machine helpers,
613
+ - script-bound / descriptor-bound machine compile helpers,
614
+ - expected-output descriptor helpers as a standalone public API.
615
+
616
+ Those lower-level primitives are kept only for internal regression and protocol research under:
617
+ - `src/internal/experimental/bond.ts`
618
+ - `examples/internal/experimental/bonds/`
619
+
620
+ ### Shared Output Binding
621
+
622
+ Bond settlement/build/verify now uses the same binding engine as Policy Core.
623
+ That means Bond and Policy return the same binding metadata vocabulary:
624
+ - `supportedForm`
625
+ - `reasonCode`
626
+ - `autoDerived`
627
+ - `fallbackReason`
628
+ - `bindingInputs`
629
+
630
+ Current practical behavior:
631
+ - `script-bound`: runtime binds next output script hash, output count, and fee output position
632
+ - `descriptor-bound`: runtime binds `output_hash(0)` when the output form is supported or when the caller supplies a manual `nextOutputHash`
633
+ - unsupported `descriptor-bound` requests fall back to `script-bound` with an explicit reason code
634
+ - supported advanced paths:
635
+ - `explicit-v1`
636
+ - `raw-output-v1`
637
+ - `manual-hash`
638
+ - current generalized/confidential story is explicit on purpose:
639
+ - unsupported high-level confidential forms still report why they fall back
640
+ - `raw-output-v1` exists for callers that already know the output bytes or already know the SHA-256 hashes of the scriptPubKey / range proof
641
+ - surjection proofs are intentionally outside this contract because Elements excludes them from `output_hash(0)`
642
+ - wallet/RPC-backed confidential auto-reconstruction is still a non-goal in this phase
643
+
644
+ You can evaluate a concrete binding scenario before building a transfer:
174
645
 
175
- - `ISSUED -> PARTIALLY_REDEEMED`
176
- - `ISSUED/PARTIALLY_REDEEMED -> REDEEMED`
177
-
178
- The next state records:
179
-
180
- - `previousStateHash`
181
- - `lastTransition.type`
182
- - `lastTransition.amount`
183
- - `lastTransition.at`
646
+ ```ts
647
+ const evaluation = sdk.outputBinding.evaluateSupport({
648
+ assetId: "bitcoin",
649
+ requestedBindingMode: "descriptor-bound",
650
+ outputForm: { amountForm: "confidential" },
651
+ });
184
652
 
185
- and the SDK verifies the principal invariant:
653
+ const rawEvaluation = sdk.outputBinding.evaluateSupport({
654
+ assetId: "unsupported-asset-alias",
655
+ requestedBindingMode: "descriptor-bound",
656
+ rawOutput: {
657
+ assetBytesHex: "01" + "22".repeat(32),
658
+ amountBytesHex: "01000000000000076c",
659
+ nonceBytesHex: "00",
660
+ scriptPubKeyHex: "5120" + "11".repeat(32),
661
+ rangeProofHex: "",
662
+ },
663
+ });
664
+ ```
186
665
 
187
- - `issuedPrincipal = outstandingPrincipal + redeemedPrincipal`
666
+ ### Bond Runtime Confidence
188
667
 
189
- On top of that, the SDK can now build a `BondSettlementDescriptor`, which bundles the intended settlement envelope into one canonical document:
668
+ Latest fresh Bond testnet reruns:
190
669
 
191
- - `definitionHash`
192
- - `previousStateHash`
193
- - `nextStateHash`
194
- - `nextContractAddress`
195
- - `nextAmountSat`
196
- - `maxFeeSat`
197
- - status progression and principal deltas
670
+ | Binding | Funding txid | Execution txid | Rerun command |
671
+ | --- | --- | --- | --- |
672
+ | `script-bound` | `1c982864ef6c83da4eb7f8018edc4cbdff439db7c6366984b3f85ad4937e2c4f` | `d659c4bdce6b32650ff58ac37ccaa55209a9f04d5dc4595f956fad034089f580` | `BOND_OUTPUT_BINDING_MODE=script-bound npm run e2e:bond-testnet` |
673
+ | `descriptor-bound` | `72d0015b51a74c3cc81f7abb74a4f6f894c7f7bbd1e83647939459d7b40e504f` | `85e0830a7b2ba33ca37d5f11bd981938418fc472e98657095680ada71387974c` | `BOND_OUTPUT_BINDING_MODE=descriptor-bound npm run e2e:bond-testnet` |
198
674
 
199
- The redemption machine commits that settlement descriptor hash as an additional anchor. This does not yet mean full runtime output introspection, but it does mean the machine can now honestly claim a committed settlement envelope instead of just a scattered set of fields.
675
+ For the current truth source and caveats, see [docs/design/bond-runtime-validation.md](./docs/design/bond-runtime-validation.md).
200
676
 
201
- Minimal TypeScript flow:
677
+ ### Minimal Bond Flow
202
678
 
203
679
  ```ts
204
- const compiled = await sdk.bonds.defineBond({
680
+ const compiled = await sdk.bonds.define({
205
681
  definitionPath: "./docs/definitions/bond-definition.json",
206
682
  issuancePath: "./docs/definitions/bond-issuance-state.json",
207
683
  simfPath: "./docs/definitions/bond-issuance-anchor.simf",
208
684
  artifactPath: "./bond-issuance.artifact.json",
209
685
  });
210
686
 
211
- const verification = await sdk.bonds.verifyBond({
687
+ const verified = await sdk.bonds.verify({
212
688
  artifactPath: "./bond-issuance.artifact.json",
213
689
  definitionPath: "./docs/definitions/bond-definition.json",
214
690
  issuancePath: "./docs/definitions/bond-issuance-state.json",
215
691
  });
216
692
 
217
- console.log(verification.crossChecks.principalInvariantValid);
218
- console.log(verification.issuance.trust.effectiveMode);
219
- ```
220
-
221
- Minimal redemption flow:
222
-
223
- ```ts
224
- const preview = await sdk.bonds.buildBondRedemption({
693
+ const redemption = await sdk.bonds.prepareRedemption({
225
694
  definitionPath: "./docs/definitions/bond-definition.json",
226
695
  previousIssuancePath: "./docs/definitions/bond-issuance-state.json",
227
696
  amount: 250000,
228
697
  redeemedAt: "2027-03-10T00:00:00Z",
698
+ nextStateSimfPath: "./docs/definitions/bond-issuance-anchor.simf",
699
+ nextAmountSat: 1900,
700
+ outputBindingMode: "script-bound",
229
701
  });
230
702
 
231
- const compiled = await sdk.bonds.redeemBond({
703
+ const settlement = await sdk.bonds.buildSettlement({
232
704
  definitionPath: "./docs/definitions/bond-definition.json",
233
705
  previousIssuancePath: "./docs/definitions/bond-issuance-state.json",
234
- amount: 250000,
235
- redeemedAt: "2027-03-10T00:00:00Z",
236
- simfPath: "./docs/definitions/bond-issuance-anchor.simf",
237
- artifactPath: "./bond-redemption.artifact.json",
238
- });
239
-
240
- const transition = await sdk.bonds.verifyBondTransition({
241
- previousIssuancePath: "./docs/definitions/bond-issuance-state.json",
242
- nextIssuancePath: "./docs/definitions/bond-issuance-state-partial-redemption.json",
706
+ nextIssuanceValue: redemption.preview.next,
707
+ nextStateSimfPath: "./docs/definitions/bond-issuance-anchor.simf",
708
+ nextAmountSat: 1900,
709
+ outputBindingMode: "script-bound",
243
710
  });
244
711
 
245
- const payload = await sdk.bonds.buildBondPayload({
246
- artifactPath: "./bond-redemption.artifact.json",
712
+ const closing = await sdk.bonds.prepareClosing({
247
713
  definitionPath: "./docs/definitions/bond-definition.json",
248
- issuancePath: "./docs/definitions/bond-issuance-state-partial-redemption.json",
714
+ redeemedIssuancePath: "./docs/definitions/bond-issuance-state-redeemed.json",
715
+ settlementDescriptorValue: settlement.descriptor,
716
+ closedAt: "2027-03-10T00:00:00Z",
249
717
  });
250
718
 
251
- const transitionPayload = await sdk.bonds.buildBondTransitionPayload({
719
+ const evidence = await sdk.bonds.exportEvidence({
720
+ artifactPath: "./bond-issuance.artifact.json",
252
721
  definitionPath: "./docs/definitions/bond-definition.json",
253
- previousIssuancePath: "./docs/definitions/bond-issuance-state.json",
254
- nextIssuancePath: "./docs/definitions/bond-issuance-state-partial-redemption.json",
722
+ issuancePath: "./docs/definitions/bond-issuance-state.json",
723
+ settlementDescriptorValue: settlement.descriptor,
255
724
  });
256
-
257
- console.log(preview.nextHash);
258
- console.log(compiled.state()?.hash);
259
- console.log(transition.transition.statusProgressionValid);
260
- console.log(payload.payload);
261
- console.log(transitionPayload.payload.redeemAmount);
262
725
  ```
263
726
 
264
- CLI equivalents:
727
+ ### Bond CLI Flow
265
728
 
266
729
  ```bash
267
- simplicity-cli state show \
268
- --type bond-issuance \
269
- --id BOND-2026-001-ISSUE-1 \
270
- --json-path ./docs/definitions/bond-issuance-state.json
271
-
272
- simplicity-cli state verify \
273
- --artifact ./bond-issuance.artifact.json \
274
- --type bond-issuance \
275
- --id BOND-2026-001-ISSUE-1 \
276
- --json-path ./docs/definitions/bond-issuance-state.json
730
+ simplicity-cli bond define \
731
+ --definition-json ./docs/definitions/bond-definition.json \
732
+ --issuance-json ./docs/definitions/bond-issuance-state.json \
733
+ --simf ./docs/definitions/bond-issuance-anchor.simf \
734
+ --artifact ./bond-issuance.artifact.json
277
735
 
278
736
  simplicity-cli bond verify \
279
737
  --artifact ./bond-issuance.artifact.json \
280
738
  --definition-json ./docs/definitions/bond-definition.json \
281
739
  --issuance-json ./docs/definitions/bond-issuance-state.json
282
740
 
283
- simplicity-cli bond redeem \
741
+ simplicity-cli bond prepare-redemption \
284
742
  --definition-json ./docs/definitions/bond-definition.json \
285
743
  --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
286
744
  --amount 250000 \
287
745
  --redeemed-at 2027-03-10T00:00:00Z \
288
- --simf ./docs/definitions/bond-issuance-anchor.simf \
289
- --next-issuance-out ./next-bond-issuance-state.json \
290
- --artifact ./bond-redemption.artifact.json
291
-
292
- simplicity-cli bond verify-transition \
293
- --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
294
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json
746
+ --next-state-simf ./docs/definitions/bond-issuance-anchor.simf \
747
+ --next-amount-sat 1900 \
748
+ --output-binding-mode script-bound \
749
+ --next-issuance-out ./next-bond-issuance-state.json
295
750
 
296
- simplicity-cli bond compile-transition \
751
+ simplicity-cli bond build-settlement \
297
752
  --definition-json ./docs/definitions/bond-definition.json \
298
753
  --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
299
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json \
300
- --simf ./docs/definitions/bond-redemption-transition.simf \
301
- --artifact ./bond-transition.artifact.json
754
+ --next-issuance-json ./next-bond-issuance-state.json \
755
+ --next-state-simf ./docs/definitions/bond-issuance-anchor.simf \
756
+ --next-amount-sat 1900 \
757
+ --output-binding-mode script-bound
302
758
 
303
- simplicity-cli bond compile-redemption-machine \
759
+ simplicity-cli bond prepare-closing \
304
760
  --definition-json ./docs/definitions/bond-definition.json \
305
- --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
306
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json \
307
- --simf ./docs/definitions/bond-redemption-state-machine.simf \
308
- --artifact ./bond-redemption-machine.artifact.json
761
+ --redeemed-issuance-json ./docs/definitions/bond-issuance-state-redeemed.json \
762
+ --settlement-descriptor-json ./bond-settlement.json \
763
+ --closed-at 2027-03-10T00:00:00Z
309
764
 
310
- simplicity-cli bond verify-machine \
311
- --artifact ./bond-redemption-machine.artifact.json \
312
- --definition-json ./docs/definitions/bond-definition.json \
313
- --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
314
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json
315
-
316
- simplicity-cli bond plan-rollover \
317
- --current-artifact ./bond-issuance.artifact.json \
765
+ simplicity-cli bond export-evidence \
766
+ --artifact ./bond-issuance.artifact.json \
318
767
  --definition-json ./docs/definitions/bond-definition.json \
319
- --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
320
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json \
321
- --next-simf ./docs/definitions/bond-issuance-anchor.simf \
322
- --next-artifact ./bond-next.artifact.json
768
+ --issuance-json ./docs/definitions/bond-issuance-state.json
323
769
 
324
- simplicity-cli bond plan-machine-rollover \
325
- --current-artifact ./bond-issuance.artifact.json \
326
- --definition-json ./docs/definitions/bond-definition.json \
327
- --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
328
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json \
329
- --machine-simf ./docs/definitions/bond-redemption-state-machine.simf \
330
- --machine-artifact ./bond-redemption-machine.artifact.json
770
+ simplicity-cli binding evaluate-support \
771
+ --asset-id bitcoin \
772
+ --output-binding-mode descriptor-bound \
773
+ --amount-form confidential
774
+ ```
331
775
 
332
- simplicity-cli bond transition-payload \
333
- --definition-json ./docs/definitions/bond-definition.json \
334
- --previous-issuance-json ./docs/definitions/bond-issuance-state.json \
335
- --next-issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json
776
+ Example `bond build-settlement` summary:
777
+
778
+ ```text
779
+ descriptorHash=4d8f...
780
+ bindingMode=descriptor-bound
781
+ previousStateHash=8c3b...
782
+ nextStateHash=56ae...
783
+ nextContractAddress=tex1p...
784
+ nextAmountSat=1900
785
+ maxFeeSat=100
786
+ supportedForm=explicit-v1
787
+ reasonCode=OK_EXPLICIT
788
+ autoDerived=true
789
+ nextOutputHash=0b9a...
790
+ bindingInputs(asset=bitcoin, amountSat=1900, nextOutputIndex=0, feeIndex=1, maxFeeSat=100)
791
+ bindingInputForms(assetForm=explicit, amountForm=explicit, nonceForm=null, rangeProofForm=empty)
792
+ ```
336
793
 
337
- simplicity-cli bond payload \
338
- --artifact ./bond-redemption.artifact.json \
339
- --definition-json ./docs/definitions/bond-definition.json \
340
- --issuance-json ./docs/definitions/bond-issuance-state-partial-redemption.json
794
+ Example `bond verify-redemption` summary:
795
+
796
+ ```text
797
+ phase=verify
798
+ mode=descriptor-bound
799
+ descriptorHash=4d8f...
800
+ nextStateHash=56ae...
801
+ nextAmountSat=1900
802
+ verified=true
803
+ bindingMode=descriptor-bound
804
+ supportedForm=explicit-v1
805
+ reasonCode=OK_EXPLICIT
806
+ autoDerived=true
807
+ nextOutputHash=0b9a...
808
+ outputBinding.mode=descriptor-bound
809
+ outputBinding.nextContractAddressCommitted=true
810
+ outputBinding.outputCountRuntimeBound=true
811
+ outputBinding.feeIndexRuntimeBound=true
812
+ outputBinding.nextOutputHashRuntimeBound=true
813
+ outputBinding.nextOutputScriptRuntimeBound=false
341
814
  ```
342
815
 
816
+ Important limitation:
817
+ - Bond finality is stronger than before, but still intentionally partial.
818
+ - `script-bound` currently runtime-binds output count, fee position, and next output script hash.
819
+ - `descriptor-bound` adds runtime `output_hash(0)` binding for supported explicit/manual-hash paths.
820
+ - exact next output amount is still not a fully generalized covenant across all output forms.
821
+ - unsupported confidential/generalized output forms fall back deterministically and report why.
822
+
823
+ For a Bond-oriented walkthrough that matches the current public surface, see [docs/definitions/README.md](./docs/definitions/README.md).
824
+ For a packaged external-consumer smoke of the public business flow, run `npm run e2e:bond-consumer`.
825
+ For the resumable Bond runtime/testnet validation flow, see [docs/design/bond-runtime-validation.md](./docs/design/bond-runtime-validation.md).
826
+
343
827
  ## Install
344
828
 
345
829
  You need three things:
@@ -1006,6 +1490,7 @@ simplicity-cli gasless request \
1006
1490
 
1007
1491
  These examples are included to help you jump to the right workflow quickly.
1008
1492
 
1493
+ Core contract workflows:
1009
1494
  - [compile-custom.ts](./examples/compile-custom.ts): compile a custom `.simf` file.
1010
1495
  - [compile-preset.ts](./examples/compile-preset.ts): compile a built-in preset.
1011
1496
  - [inspect-contract.ts](./examples/inspect-contract.ts): inspect a contract spend before broadcast.
@@ -1015,21 +1500,28 @@ These examples are included to help you jump to the right workflow quickly.
1015
1500
  - [execute-htlc.ts](./examples/execute-htlc.ts): HTLC preset with custom witness values.
1016
1501
  - [execute-transfer-with-timeout-cooperative.ts](./examples/execute-transfer-with-timeout-cooperative.ts): cooperative multi-witness timeout flow.
1017
1502
  - [gasless-transfer.ts](./examples/gasless-transfer.ts): standard relayer-backed gasless L-BTC transfer.
1018
- - [define-bond.ts](./examples/define-bond.ts): compile a bond example with a trusted definition hash anchor.
1019
- - [show-bond-definition.ts](./examples/show-bond-definition.ts): verify and retrieve a trusted bond definition from JSON + artifact.
1020
- - [define-bond-issuance.ts](./examples/define-bond-issuance.ts): compile a bond example with both trusted definition and issuance state anchors.
1021
- - [show-bond-issuance.ts](./examples/show-bond-issuance.ts): load a bond artifact together with its verified issuance state.
1022
- - [verify-bond-issuance.ts](./examples/verify-bond-issuance.ts): run combined Bond definition/state verification and invariant checks.
1023
- - [redeem-bond-issuance.ts](./examples/redeem-bond-issuance.ts): build the next redemption state and compile a new anchored artifact.
1024
- - [verify-bond-transition.ts](./examples/verify-bond-transition.ts): verify a previous/next issuance state transition.
1025
- - [compile-bond-transition.ts](./examples/compile-bond-transition.ts): compile a transition contract that commits both previous and next issuance state hashes.
1026
- - [compile-bond-redemption-machine.ts](./examples/compile-bond-redemption-machine.ts): compile a redemption transition contract that also commits redeem amount and transition kind.
1027
- - [verify-bond-redemption-machine.ts](./examples/verify-bond-redemption-machine.ts): verify a compiled redemption machine artifact against definition, previous state, and next state inputs.
1028
- - [plan-bond-rollover.ts](./examples/plan-bond-rollover.ts): build a runtime rollover plan that spends the current state UTXO into the next state's contract address.
1029
- - [show-bond-transition-payload.ts](./examples/show-bond-transition-payload.ts): emit a bridge-ready payload for a previous/next redemption transition.
1030
- - [show-bond-payload.ts](./examples/show-bond-payload.ts): emit a bridge-ready payload from a verified bond artifact.
1031
- - [redeem-bond-issuance.ts](./examples/redeem-bond-issuance.ts): build a partially redeemed bond issuance state and anchor it in a new artifact.
1032
- - [verify-bond-transition.ts](./examples/verify-bond-transition.ts): verify a redemption transition between two issuance state documents.
1503
+
1504
+ Policy Core examples:
1505
+ - [describe-policy-template.ts](./examples/describe-policy-template.ts): inspect a public policy manifest and validate params.
1506
+ - [show-required-policy-transfer.ts](./examples/show-required-policy-transfer.ts): preview a required 1tx recursive transfer.
1507
+ - [show-optional-policy-transfer.ts](./examples/show-optional-policy-transfer.ts): preview an optional plain-or-recursive transfer.
1508
+ - [execute-required-policy-transfer.ts](./examples/execute-required-policy-transfer.ts): execute a funded required policy UTXO.
1509
+ - [execute-optional-policy-transfer.ts](./examples/execute-optional-policy-transfer.ts): execute an optional plain or recursive branch.
1510
+ - [custom-recursive-delay-required.manifest.json](./examples/custom-recursive-delay-required.manifest.json): example external manifest for custom template loading.
1511
+
1512
+ Bond business-layer examples:
1513
+ - [define-bond.ts](./examples/define-bond.ts): compile a bond definition anchor with the generic contract API.
1514
+ - [show-bond-definition.ts](./examples/show-bond-definition.ts): verify and retrieve a trusted bond definition.
1515
+ - [define-bond-issuance.ts](./examples/define-bond-issuance.ts): define a bond issuance artifact.
1516
+ - [show-bond-issuance.ts](./examples/show-bond-issuance.ts): load a bond artifact with verified issuance state.
1517
+ - [verify-bond-issuance.ts](./examples/verify-bond-issuance.ts): run bond invariant checks against artifact + JSON inputs.
1518
+ - [show-bond-business-flow.ts](./examples/show-bond-business-flow.ts): walk the business-layer flow from definition through finality payload export.
1519
+ - [redeem-bond-issuance.ts](./examples/redeem-bond-issuance.ts): prepare a bond redemption preview and next issuance state.
1520
+ - [show-bond-settlement-payload.ts](./examples/show-bond-settlement-payload.ts): build a public settlement descriptor.
1521
+ - [verify-bond-settlement.ts](./examples/verify-bond-settlement.ts): verify a settlement descriptor against bond inputs.
1522
+
1523
+ Internal / experimental Bond regressions:
1524
+ - [examples/internal/experimental/bonds/README.md](./examples/internal/experimental/bonds/README.md): low-level machine / rollover / transition helpers retained for research and regression only.
1033
1525
 
1034
1526
  In addition to the in-repo examples, the package has also been validated from a blank external consumer project with:
1035
1527
  - `npm install @hazbase/simplicity`
@@ -1037,6 +1529,11 @@ In addition to the in-repo examples, the package has also been validated from a
1037
1529
  - preset compile -> fund -> inspect -> execute
1038
1530
  - custom `.simf` compile -> fund -> inspect -> execute
1039
1531
  - relayer-backed gasless execution
1532
+ - policy quickstart smoke via `npm run e2e:policy-consumer`
1533
+
1534
+ ## Covenant Roadmap
1535
+
1536
+ If you want to see how the current bond lifecycle work can evolve toward stronger output binding, see [docs/design/full-covenant-output-binding.md](./docs/design/full-covenant-output-binding.md). That note captures what the local SimplicityHL examples appear to expose today and what the next realistic covenant milestones are.
1040
1537
 
1041
1538
  ## FAQ / Practical Notes
1042
1539