@hazbase/simplicity 0.0.4 → 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.
- package/README.md +679 -42
- package/dist/cli.js +2268 -5
- package/dist/client/SimplicityClient.d.ts +64 -25
- package/dist/client/SimplicityClient.js +65 -3
- package/dist/core/executor.js +67 -92
- package/dist/core/outputBinding.d.ts +61 -0
- package/dist/core/outputBinding.js +552 -0
- package/dist/core/schnorr.d.ts +5 -0
- package/dist/core/schnorr.js +34 -0
- package/dist/core/types.d.ts +586 -1
- package/dist/docs/definitions/bond-anchor.simf +19 -0
- package/dist/docs/definitions/bond-definition.json +10 -0
- package/dist/docs/definitions/bond-descriptor-bound-settlement-machine.simf +144 -0
- package/dist/docs/definitions/bond-issuance-anchor.simf +26 -0
- package/dist/docs/definitions/bond-issuance-state-partial-redemption.json +18 -0
- package/dist/docs/definitions/bond-issuance-state-redeemed.json +18 -0
- package/dist/docs/definitions/bond-issuance-state.json +12 -0
- package/dist/docs/definitions/bond-redemption-state-machine.simf +118 -0
- package/dist/docs/definitions/bond-redemption-transition.simf +41 -0
- package/dist/docs/definitions/bond-script-bound-settlement-machine.simf +142 -0
- package/dist/docs/definitions/fund-capital-call-open.simf +82 -0
- package/dist/docs/definitions/fund-capital-call-refund-only.simf +33 -0
- package/dist/docs/definitions/fund-capital-call-state.json +11 -0
- package/dist/docs/definitions/fund-definition.json +8 -0
- package/dist/docs/definitions/fund-distribution-claim.simf +57 -0
- package/dist/docs/definitions/recursive-delay-direct-next.simf +60 -0
- package/dist/docs/definitions/recursive-delay-optional.simf +88 -0
- package/dist/docs/definitions/recursive-delay-required.simf +72 -0
- package/dist/docs/definitions/recursive-delay.simf +83 -0
- package/dist/docs/definitions/recursive-policy-transfer-machine.simf +65 -0
- package/dist/domain/bond.d.ts +9855 -1
- package/dist/domain/bond.js +2156 -1
- package/dist/domain/bondSettlementValidation.d.ts +20 -0
- package/dist/domain/bondSettlementValidation.js +150 -0
- package/dist/domain/bondValidation.d.ts +26 -0
- package/dist/domain/bondValidation.js +278 -3
- package/dist/domain/fund.d.ts +2069 -0
- package/dist/domain/fund.js +1384 -0
- package/dist/domain/fundValidation.d.ts +122 -0
- package/dist/domain/fundValidation.js +635 -0
- package/dist/domain/policies.d.ts +1051 -0
- package/dist/domain/policies.js +1605 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +92 -1
- 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,
|
|
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,80 +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
|
|
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
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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:
|
|
645
|
+
|
|
646
|
+
```ts
|
|
647
|
+
const evaluation = sdk.outputBinding.evaluateSupport({
|
|
648
|
+
assetId: "bitcoin",
|
|
649
|
+
requestedBindingMode: "descriptor-bound",
|
|
650
|
+
outputForm: { amountForm: "confidential" },
|
|
651
|
+
});
|
|
652
|
+
|
|
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
|
+
});
|
|
171
664
|
```
|
|
172
665
|
|
|
173
|
-
|
|
666
|
+
### Bond Runtime Confidence
|
|
667
|
+
|
|
668
|
+
Latest fresh Bond testnet reruns:
|
|
669
|
+
|
|
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` |
|
|
674
|
+
|
|
675
|
+
For the current truth source and caveats, see [docs/design/bond-runtime-validation.md](./docs/design/bond-runtime-validation.md).
|
|
676
|
+
|
|
677
|
+
### Minimal Bond Flow
|
|
174
678
|
|
|
175
679
|
```ts
|
|
176
|
-
const compiled = await sdk.bonds.
|
|
680
|
+
const compiled = await sdk.bonds.define({
|
|
177
681
|
definitionPath: "./docs/definitions/bond-definition.json",
|
|
178
682
|
issuancePath: "./docs/definitions/bond-issuance-state.json",
|
|
179
683
|
simfPath: "./docs/definitions/bond-issuance-anchor.simf",
|
|
180
684
|
artifactPath: "./bond-issuance.artifact.json",
|
|
181
685
|
});
|
|
182
686
|
|
|
183
|
-
const
|
|
687
|
+
const verified = await sdk.bonds.verify({
|
|
184
688
|
artifactPath: "./bond-issuance.artifact.json",
|
|
185
689
|
definitionPath: "./docs/definitions/bond-definition.json",
|
|
186
690
|
issuancePath: "./docs/definitions/bond-issuance-state.json",
|
|
187
691
|
});
|
|
188
692
|
|
|
189
|
-
|
|
190
|
-
|
|
693
|
+
const redemption = await sdk.bonds.prepareRedemption({
|
|
694
|
+
definitionPath: "./docs/definitions/bond-definition.json",
|
|
695
|
+
previousIssuancePath: "./docs/definitions/bond-issuance-state.json",
|
|
696
|
+
amount: 250000,
|
|
697
|
+
redeemedAt: "2027-03-10T00:00:00Z",
|
|
698
|
+
nextStateSimfPath: "./docs/definitions/bond-issuance-anchor.simf",
|
|
699
|
+
nextAmountSat: 1900,
|
|
700
|
+
outputBindingMode: "script-bound",
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
const settlement = await sdk.bonds.buildSettlement({
|
|
704
|
+
definitionPath: "./docs/definitions/bond-definition.json",
|
|
705
|
+
previousIssuancePath: "./docs/definitions/bond-issuance-state.json",
|
|
706
|
+
nextIssuanceValue: redemption.preview.next,
|
|
707
|
+
nextStateSimfPath: "./docs/definitions/bond-issuance-anchor.simf",
|
|
708
|
+
nextAmountSat: 1900,
|
|
709
|
+
outputBindingMode: "script-bound",
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
const closing = await sdk.bonds.prepareClosing({
|
|
713
|
+
definitionPath: "./docs/definitions/bond-definition.json",
|
|
714
|
+
redeemedIssuancePath: "./docs/definitions/bond-issuance-state-redeemed.json",
|
|
715
|
+
settlementDescriptorValue: settlement.descriptor,
|
|
716
|
+
closedAt: "2027-03-10T00:00:00Z",
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const evidence = await sdk.bonds.exportEvidence({
|
|
720
|
+
artifactPath: "./bond-issuance.artifact.json",
|
|
721
|
+
definitionPath: "./docs/definitions/bond-definition.json",
|
|
722
|
+
issuancePath: "./docs/definitions/bond-issuance-state.json",
|
|
723
|
+
settlementDescriptorValue: settlement.descriptor,
|
|
724
|
+
});
|
|
191
725
|
```
|
|
192
726
|
|
|
193
|
-
CLI
|
|
727
|
+
### Bond CLI Flow
|
|
194
728
|
|
|
195
729
|
```bash
|
|
196
|
-
simplicity-cli
|
|
197
|
-
--
|
|
198
|
-
--
|
|
199
|
-
--
|
|
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
|
|
200
735
|
|
|
201
|
-
simplicity-cli
|
|
736
|
+
simplicity-cli bond verify \
|
|
202
737
|
--artifact ./bond-issuance.artifact.json \
|
|
203
|
-
--
|
|
204
|
-
--
|
|
205
|
-
--json-path ./docs/definitions/bond-issuance-state.json
|
|
738
|
+
--definition-json ./docs/definitions/bond-definition.json \
|
|
739
|
+
--issuance-json ./docs/definitions/bond-issuance-state.json
|
|
206
740
|
|
|
207
|
-
simplicity-cli bond
|
|
741
|
+
simplicity-cli bond prepare-redemption \
|
|
742
|
+
--definition-json ./docs/definitions/bond-definition.json \
|
|
743
|
+
--previous-issuance-json ./docs/definitions/bond-issuance-state.json \
|
|
744
|
+
--amount 250000 \
|
|
745
|
+
--redeemed-at 2027-03-10T00:00:00Z \
|
|
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
|
|
750
|
+
|
|
751
|
+
simplicity-cli bond build-settlement \
|
|
752
|
+
--definition-json ./docs/definitions/bond-definition.json \
|
|
753
|
+
--previous-issuance-json ./docs/definitions/bond-issuance-state.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
|
|
758
|
+
|
|
759
|
+
simplicity-cli bond prepare-closing \
|
|
760
|
+
--definition-json ./docs/definitions/bond-definition.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
|
|
764
|
+
|
|
765
|
+
simplicity-cli bond export-evidence \
|
|
208
766
|
--artifact ./bond-issuance.artifact.json \
|
|
209
767
|
--definition-json ./docs/definitions/bond-definition.json \
|
|
210
768
|
--issuance-json ./docs/definitions/bond-issuance-state.json
|
|
769
|
+
|
|
770
|
+
simplicity-cli binding evaluate-support \
|
|
771
|
+
--asset-id bitcoin \
|
|
772
|
+
--output-binding-mode descriptor-bound \
|
|
773
|
+
--amount-form confidential
|
|
774
|
+
```
|
|
775
|
+
|
|
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
|
+
```
|
|
793
|
+
|
|
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
|
|
211
814
|
```
|
|
212
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
|
+
|
|
213
827
|
## Install
|
|
214
828
|
|
|
215
829
|
You need three things:
|
|
@@ -876,6 +1490,7 @@ simplicity-cli gasless request \
|
|
|
876
1490
|
|
|
877
1491
|
These examples are included to help you jump to the right workflow quickly.
|
|
878
1492
|
|
|
1493
|
+
Core contract workflows:
|
|
879
1494
|
- [compile-custom.ts](./examples/compile-custom.ts): compile a custom `.simf` file.
|
|
880
1495
|
- [compile-preset.ts](./examples/compile-preset.ts): compile a built-in preset.
|
|
881
1496
|
- [inspect-contract.ts](./examples/inspect-contract.ts): inspect a contract spend before broadcast.
|
|
@@ -885,11 +1500,28 @@ These examples are included to help you jump to the right workflow quickly.
|
|
|
885
1500
|
- [execute-htlc.ts](./examples/execute-htlc.ts): HTLC preset with custom witness values.
|
|
886
1501
|
- [execute-transfer-with-timeout-cooperative.ts](./examples/execute-transfer-with-timeout-cooperative.ts): cooperative multi-witness timeout flow.
|
|
887
1502
|
- [gasless-transfer.ts](./examples/gasless-transfer.ts): standard relayer-backed gasless L-BTC transfer.
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
- [
|
|
891
|
-
- [show-
|
|
892
|
-
- [
|
|
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.
|
|
893
1525
|
|
|
894
1526
|
In addition to the in-repo examples, the package has also been validated from a blank external consumer project with:
|
|
895
1527
|
- `npm install @hazbase/simplicity`
|
|
@@ -897,6 +1529,11 @@ In addition to the in-repo examples, the package has also been validated from a
|
|
|
897
1529
|
- preset compile -> fund -> inspect -> execute
|
|
898
1530
|
- custom `.simf` compile -> fund -> inspect -> execute
|
|
899
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.
|
|
900
1537
|
|
|
901
1538
|
## FAQ / Practical Notes
|
|
902
1539
|
|