@hazbase/simplicity 0.4.1 → 0.4.3

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.
@@ -5,8 +5,13 @@ exports.runSimcCompile = runSimcCompile;
5
5
  exports.runSimcWithWitness = runSimcWithWitness;
6
6
  exports.runHalInfo = runHalInfo;
7
7
  exports.runHalUpdateInput = runHalUpdateInput;
8
+ exports.runHalCreatePset = runHalCreatePset;
9
+ exports.runSimplicityCreatePset = runSimplicityCreatePset;
10
+ exports.runSimplicityUpdateInput = runSimplicityUpdateInput;
11
+ exports.runSimplicityBlindPset = runSimplicityBlindPset;
8
12
  exports.runHalSighash = runHalSighash;
9
13
  exports.runHalFinalize = runHalFinalize;
14
+ exports.runSimplicityFinalize = runSimplicityFinalize;
10
15
  exports.runHalExtract = runHalExtract;
11
16
  const node_child_process_1 = require("node:child_process");
12
17
  const node_util_1 = require("node:util");
@@ -21,7 +26,13 @@ async function runCommand(command, args, options = {}) {
21
26
  return { stdout: stdout.trim(), stderr: stderr.trim() };
22
27
  }
23
28
  catch (error) {
24
- throw new errors_1.ToolchainError(`Command failed: ${command} ${args.join(" ")}`, error);
29
+ const cause = error;
30
+ const details = [
31
+ cause.message ? `message=${cause.message}` : "",
32
+ cause.stderr ? `stderr=${cause.stderr.trim()}` : "",
33
+ cause.stdout ? `stdout=${cause.stdout.trim()}` : "",
34
+ ].filter(Boolean);
35
+ throw new errors_1.ToolchainError(`Command failed: ${command} ${args.slice(0, 3).join(" ")}${details.length ? ` | ${details.join(" | ")}` : ""}`, error);
25
36
  }
26
37
  }
27
38
  async function runSimcCompile(simcPath, simfPath) {
@@ -41,6 +52,7 @@ async function runHalUpdateInput(halPath, pset, inputIndex, utxoSpec, cmr, inter
41
52
  "simplicity",
42
53
  "pset",
43
54
  "update-input",
55
+ "--liquid",
44
56
  pset,
45
57
  String(inputIndex),
46
58
  "-i",
@@ -52,10 +64,73 @@ async function runHalUpdateInput(halPath, pset, inputIndex, utxoSpec, cmr, inter
52
64
  ]);
53
65
  return JSON.parse(result.stdout);
54
66
  }
67
+ async function runHalCreatePset(halPath, inputs, outputs) {
68
+ const result = await runCommand(halPath, [
69
+ "simplicity",
70
+ "pset",
71
+ "create",
72
+ "--liquid",
73
+ JSON.stringify(inputs),
74
+ JSON.stringify(outputs),
75
+ ]);
76
+ return JSON.parse(result.stdout);
77
+ }
78
+ async function runSimplicityCreatePset(halPath, inputs, outputs) {
79
+ const helperPath = process.env.HAZBASE_SIMPLICITY_CREATE_PATH ?? "hazbase-simplicity-create";
80
+ try {
81
+ const helper = await runCommand(helperPath, [
82
+ "--liquid",
83
+ JSON.stringify(inputs),
84
+ JSON.stringify(outputs),
85
+ ]);
86
+ return JSON.parse(helper.stdout);
87
+ }
88
+ catch (error) {
89
+ const message = error instanceof Error ? error.message : String(error);
90
+ if (!message.includes("ENOENT")) {
91
+ return {
92
+ error: message,
93
+ };
94
+ }
95
+ }
96
+ return runHalCreatePset(halPath, inputs, outputs);
97
+ }
98
+ async function runSimplicityUpdateInput(halPath, pset, inputIndex, inputUtxo, cmr, internalKey) {
99
+ const helperPath = process.env.HAZBASE_SIMPLICITY_UPDATE_INPUT_PATH ?? "hazbase-simplicity-update-input";
100
+ try {
101
+ const helper = await runCommand(helperPath, [
102
+ "--liquid",
103
+ pset,
104
+ String(inputIndex),
105
+ internalKey,
106
+ cmr,
107
+ ]);
108
+ return JSON.parse(helper.stdout);
109
+ }
110
+ catch (error) {
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ if (!message.includes("ENOENT")) {
113
+ return {
114
+ error: message,
115
+ };
116
+ }
117
+ }
118
+ return runHalUpdateInput(halPath, pset, inputIndex, inputUtxo, cmr, internalKey);
119
+ }
120
+ async function runSimplicityBlindPset(pset, inputSecrets) {
121
+ const helperPath = process.env.HAZBASE_SIMPLICITY_BLIND_PSET_PATH ?? "hazbase-simplicity-blind-pset";
122
+ const helper = await runCommand(helperPath, [
123
+ "--liquid",
124
+ pset,
125
+ JSON.stringify(inputSecrets),
126
+ ]);
127
+ return JSON.parse(helper.stdout);
128
+ }
55
129
  async function runHalSighash(halPath, pset, inputIndex, cmr, privkeyHex) {
56
130
  const result = await runCommand(halPath, [
57
131
  "simplicity",
58
132
  "sighash",
133
+ "--liquid",
59
134
  pset,
60
135
  String(inputIndex),
61
136
  cmr,
@@ -69,6 +144,7 @@ async function runHalFinalize(halPath, pset, inputIndex, program, witness) {
69
144
  "simplicity",
70
145
  "pset",
71
146
  "finalize",
147
+ "--liquid",
72
148
  pset,
73
149
  String(inputIndex),
74
150
  program,
@@ -76,7 +152,35 @@ async function runHalFinalize(halPath, pset, inputIndex, program, witness) {
76
152
  ]);
77
153
  return JSON.parse(result.stdout);
78
154
  }
155
+ async function runSimplicityFinalize(halPath, pset, inputIndex, program, witness, options = {}) {
156
+ const helperPath = process.env.HAZBASE_SIMPLICITY_FINALIZE_PATH ?? "hazbase-simplicity-finalize";
157
+ if (options.redeemProgram) {
158
+ try {
159
+ const helper = await runCommand(helperPath, [
160
+ "--liquid",
161
+ pset,
162
+ String(inputIndex),
163
+ options.redeemProgram,
164
+ witness,
165
+ ]);
166
+ return JSON.parse(helper.stdout);
167
+ }
168
+ catch (error) {
169
+ const message = error instanceof Error ? error.message : String(error);
170
+ if (!message.includes("ENOENT")) {
171
+ const halFallback = await runHalFinalize(halPath, pset, inputIndex, program, witness);
172
+ if (halFallback.pset)
173
+ return halFallback;
174
+ return {
175
+ ...halFallback,
176
+ helperError: message,
177
+ };
178
+ }
179
+ }
180
+ }
181
+ return runHalFinalize(halPath, pset, inputIndex, program, witness);
182
+ }
79
183
  async function runHalExtract(halPath, pset) {
80
- const result = await runCommand(halPath, ["simplicity", "pset", "extract", pset]);
184
+ const result = await runCommand(halPath, ["simplicity", "pset", "extract", "--liquid", pset]);
81
185
  return result.stdout;
82
186
  }
@@ -313,6 +313,50 @@ export interface ExecuteResult {
313
313
  broadcasted: boolean;
314
314
  contractUtxo: ContractUtxo;
315
315
  }
316
+ export interface MultiAssetContractInput {
317
+ txid: string;
318
+ vout: number;
319
+ asset: string;
320
+ amountSat: number;
321
+ sequence?: number;
322
+ amountBlinder?: string;
323
+ assetBlinder?: string;
324
+ }
325
+ export interface MultiAssetContractOutput {
326
+ address: string;
327
+ asset: string;
328
+ amountSat: number;
329
+ }
330
+ export interface MultiAssetContractCallInput {
331
+ wallet: string;
332
+ signer: SignerConfig;
333
+ witness?: WitnessConfig;
334
+ contractInput?: {
335
+ txid: string;
336
+ vout?: number;
337
+ asset?: string;
338
+ amountSat?: number;
339
+ rawTxHex?: string;
340
+ blindingPrivateKey?: string;
341
+ };
342
+ extraInputs?: MultiAssetContractInput[];
343
+ outputs: MultiAssetContractOutput[];
344
+ feeSat?: number;
345
+ changeAddress?: string;
346
+ purpose?: string;
347
+ locktimeHeight?: number;
348
+ broadcast?: boolean;
349
+ }
350
+ export interface MultiAssetInspectResult extends InspectResult {
351
+ extraInputs: MultiAssetContractInput[];
352
+ requestedOutputs: MultiAssetContractOutput[];
353
+ changeOutputs: MultiAssetContractOutput[];
354
+ }
355
+ export interface MultiAssetExecuteResult extends ExecuteResult {
356
+ extraInputs: MultiAssetContractInput[];
357
+ requestedOutputs: MultiAssetContractOutput[];
358
+ changeOutputs: MultiAssetContractOutput[];
359
+ }
316
360
  export interface GaslessExecuteInput {
317
361
  relayer?: import("../gasless/RelayerClient").RelayerClient;
318
362
  fromLabel?: string;
@@ -0,0 +1,128 @@
1
+ /*
2
+ * RWA DvP escrow machine.
3
+ *
4
+ * Delivery path:
5
+ * - output 0 is the payment asset sent to treasury.
6
+ * - output 1 is the Liquid RWA asset sent to the buyer.
7
+ *
8
+ * Refund path:
9
+ * - output 0 is the payment asset returned to the refund recipient after
10
+ * TIMEOUT_HEIGHT.
11
+ *
12
+ * The SDK supplies output hash/script hash witnesses and signs sig_all_hash,
13
+ * so the operator signature covers the full transaction assembled by the SDK.
14
+ */
15
+ fn not(bit: bool) -> bool {
16
+ <u1>::into(jet::complement_1(<bool>::into(bit)))
17
+ }
18
+
19
+ fn require_hash_anchor(value: u256) {
20
+ let zero_hash: u256 = 0x0000000000000000000000000000000000000000000000000000000000000000;
21
+ assert!(not(jet::eq_256(value, zero_hash)));
22
+ }
23
+
24
+ fn require_terms_anchor() {
25
+ let terms_hash: u256 = 0x{{TERMS_HASH}};
26
+ require_hash_anchor(terms_hash);
27
+ }
28
+
29
+ fn require_policy_anchor() {
30
+ let policy_hash: u256 = 0x{{POLICY_HASH}};
31
+ require_hash_anchor(policy_hash);
32
+ }
33
+
34
+ fn require_bound_output(actual_output_hash: u256, actual_script_hash: u256, expected_output_hash: u256, expected_script_hash: u256, binding_mode: u8) {
35
+ match jet::eq_8(binding_mode, 0x03) {
36
+ true => {},
37
+ false => match jet::eq_8(binding_mode, 0x01) {
38
+ true => assert!(jet::eq_256(actual_output_hash, expected_output_hash)),
39
+ false => assert!(jet::eq_256(actual_script_hash, expected_script_hash)),
40
+ },
41
+ };
42
+ }
43
+
44
+ fn require_output_0(expected_output_hash: u256, expected_script_hash: u256, binding_mode: u8) {
45
+ let actual_output_hash: u256 = match jet::output_hash(0) {
46
+ Some(output_hash : u256) => output_hash,
47
+ None => panic!(),
48
+ };
49
+ let actual_script_hash: u256 = unwrap(jet::output_script_hash(0));
50
+ require_bound_output(actual_output_hash, actual_script_hash, expected_output_hash, expected_script_hash, binding_mode);
51
+ }
52
+
53
+ fn require_output_1(expected_output_hash: u256, expected_script_hash: u256, binding_mode: u8) {
54
+ let actual_output_hash: u256 = match jet::output_hash(1) {
55
+ Some(output_hash : u256) => output_hash,
56
+ None => panic!(),
57
+ };
58
+ let actual_script_hash: u256 = unwrap(jet::output_script_hash(1));
59
+ require_bound_output(actual_output_hash, actual_script_hash, expected_output_hash, expected_script_hash, binding_mode);
60
+ }
61
+
62
+ fn checksig(sig: Signature) {
63
+ let signer: Pubkey = 0x{{OPERATOR_XONLY}};
64
+ jet::bip_0340_verify((signer, jet::sig_all_hash()), sig);
65
+ }
66
+
67
+ fn delivery_spend(
68
+ payment_output_hash: u256,
69
+ payment_output_script_hash: u256,
70
+ payment_output_binding_mode: u8,
71
+ rwa_output_hash: u256,
72
+ rwa_output_script_hash: u256,
73
+ rwa_output_binding_mode: u8,
74
+ signer_signature: Signature
75
+ ) {
76
+ require_output_0(
77
+ payment_output_hash,
78
+ payment_output_script_hash,
79
+ payment_output_binding_mode
80
+ );
81
+ require_output_1(
82
+ rwa_output_hash,
83
+ rwa_output_script_hash,
84
+ rwa_output_binding_mode
85
+ );
86
+ checksig(signer_signature);
87
+ }
88
+
89
+ fn refund_spend(
90
+ refund_output_hash: u256,
91
+ refund_output_script_hash: u256,
92
+ refund_output_binding_mode: u8,
93
+ signer_signature: Signature
94
+ ) {
95
+ jet::check_lock_height({{TIMEOUT_HEIGHT}});
96
+ require_output_0(
97
+ refund_output_hash,
98
+ refund_output_script_hash,
99
+ refund_output_binding_mode
100
+ );
101
+ checksig(signer_signature);
102
+ }
103
+
104
+ fn main() {
105
+ require_terms_anchor();
106
+ require_policy_anchor();
107
+ let signer_signature: Signature = witness::SIGNER_SIGNATURE;
108
+ match witness::DELIVERY_OR_REFUND {
109
+ Some(marker: u8) => {
110
+ assert!(jet::eq_8(marker, 0x01));
111
+ delivery_spend(
112
+ witness::PAYMENT_OUTPUT_HASH,
113
+ witness::PAYMENT_OUTPUT_SCRIPT_HASH,
114
+ witness::PAYMENT_OUTPUT_BINDING_MODE,
115
+ witness::RWA_OUTPUT_HASH,
116
+ witness::RWA_OUTPUT_SCRIPT_HASH,
117
+ witness::RWA_OUTPUT_BINDING_MODE,
118
+ signer_signature
119
+ )
120
+ },
121
+ None => refund_spend(
122
+ witness::REFUND_OUTPUT_HASH,
123
+ witness::REFUND_OUTPUT_SCRIPT_HASH,
124
+ witness::REFUND_OUTPUT_BINDING_MODE,
125
+ signer_signature
126
+ ),
127
+ }
128
+ }
@@ -1,5 +1,5 @@
1
1
  import type { SimplicityClient } from "../client/SimplicityClient";
2
- import type { BondOutputBindingMode, OutputRawFields } from "../core/types";
2
+ import type { BondOutputBindingMode, MultiAssetContractInput, MultiAssetExecuteResult, MultiAssetInspectResult, OutputRawFields, SignerConfig, SimplicityArtifact, WitnessConfig } from "../core/types";
3
3
  import { type LiquidX402AssetKey, type LiquidX402Network, type LiquidX402PaymentPayload, type LiquidX402PaymentRequirements, type LiquidX402VerifyPaymentResult } from "../x402";
4
4
  export declare const RWA_DVP_PURCHASE_SCHEMA_VERSION: "rwa-dvp-purchase/v1";
5
5
  export declare const RWA_DVP_DELIVERY_CLAIM_SCHEMA_VERSION: "rwa-dvp-delivery-claim/v1";
@@ -7,10 +7,12 @@ export declare const RWA_DVP_REFUND_CLAIM_SCHEMA_VERSION: "rwa-dvp-refund-claim/
7
7
  export declare const RWA_DVP_VERIFICATION_SCHEMA_VERSION: "rwa-dvp-verification/v1";
8
8
  export declare const RWA_DVP_EVIDENCE_SCHEMA_VERSION: "rwa-dvp-evidence/v1";
9
9
  export type RwaDvpPaymentAsset = LiquidX402AssetKey;
10
+ export type RwaDvpEvmTokenStandard = "ERC3475" | "ERC20" | "ERC721" | "ERC1155";
10
11
  export interface RwaDvpEvmLockReference {
11
12
  chainId: number;
12
13
  lockManager: string;
13
14
  orderKey: string;
15
+ tokenStandard?: RwaDvpEvmTokenStandard;
14
16
  token?: string;
15
17
  backingOwner?: string;
16
18
  classId?: string;
@@ -190,6 +192,74 @@ export interface RwaDvpPrepareRefundClaimInput {
190
192
  refundTxid?: string;
191
193
  createdAt?: string | Date;
192
194
  }
195
+ export interface RwaDvpCompileEscrowContractInput {
196
+ purchase: RwaDvpPurchaseDefinition;
197
+ operatorXonly: string;
198
+ timeoutHeight: number;
199
+ simfPath?: string;
200
+ }
201
+ export interface RwaDvpCompiledEscrowContract {
202
+ compiled: Awaited<ReturnType<SimplicityClient["compileFromFile"]>>;
203
+ artifact: SimplicityArtifact;
204
+ contractAddress: string;
205
+ timeoutHeight: number;
206
+ termsHash: string;
207
+ policyHash: string;
208
+ }
209
+ export interface RwaDvpClaimOutputBinding {
210
+ outputHash: string;
211
+ outputScriptHash: string;
212
+ bindingMode: BondOutputBindingMode;
213
+ }
214
+ export interface RwaDvpClaimExecutionBaseInput {
215
+ purchase: RwaDvpPurchaseDefinition;
216
+ artifactPath?: string;
217
+ artifact?: SimplicityArtifact;
218
+ wallet: string;
219
+ signer: SignerConfig;
220
+ feeSat?: number;
221
+ changeAddress?: string;
222
+ extraInputs?: MultiAssetContractInput[];
223
+ contractInputRawTxHex?: string;
224
+ contractInputBlindingPrivateKey?: string;
225
+ witness?: WitnessConfig;
226
+ locktimeHeight?: number;
227
+ }
228
+ export interface RwaDvpInspectDeliveryClaimInput extends RwaDvpClaimExecutionBaseInput {
229
+ descriptor: RwaDvpDeliveryClaimDescriptor;
230
+ }
231
+ export interface RwaDvpExecuteDeliveryClaimInput extends RwaDvpInspectDeliveryClaimInput {
232
+ broadcast?: boolean;
233
+ }
234
+ export interface RwaDvpInspectRefundClaimInput extends RwaDvpClaimExecutionBaseInput {
235
+ descriptor: RwaDvpRefundClaimDescriptor;
236
+ }
237
+ export interface RwaDvpExecuteRefundClaimInput extends RwaDvpInspectRefundClaimInput {
238
+ broadcast?: boolean;
239
+ }
240
+ export interface RwaDvpDeliveryClaimInspection {
241
+ descriptor: RwaDvpDeliveryClaimDescriptor;
242
+ verification: RwaDvpVerificationReport;
243
+ outputBinding: {
244
+ paymentToTreasury: RwaDvpClaimOutputBinding;
245
+ rwaToBuyer: RwaDvpClaimOutputBinding;
246
+ };
247
+ inspect: MultiAssetInspectResult;
248
+ }
249
+ export interface RwaDvpDeliveryClaimExecution extends Omit<RwaDvpDeliveryClaimInspection, "inspect"> {
250
+ execution: MultiAssetExecuteResult;
251
+ }
252
+ export interface RwaDvpRefundClaimInspection {
253
+ descriptor: RwaDvpRefundClaimDescriptor;
254
+ verification: RwaDvpVerificationReport;
255
+ outputBinding: {
256
+ refund: RwaDvpClaimOutputBinding;
257
+ };
258
+ inspect: MultiAssetInspectResult;
259
+ }
260
+ export interface RwaDvpRefundClaimExecution extends Omit<RwaDvpRefundClaimInspection, "inspect"> {
261
+ execution: MultiAssetExecuteResult;
262
+ }
193
263
  export interface RwaDvpVerificationReport {
194
264
  schemaVersion: typeof RWA_DVP_VERIFICATION_SCHEMA_VERSION;
195
265
  ok: boolean;
@@ -239,6 +309,11 @@ export declare function verifyRefundClaim(_sdk: SimplicityClient, input: {
239
309
  purchase: RwaDvpPurchaseDefinition;
240
310
  descriptor: RwaDvpRefundClaimDescriptor;
241
311
  }): RwaDvpVerificationReport;
312
+ export declare function compileEscrowContract(sdk: SimplicityClient, input: RwaDvpCompileEscrowContractInput): Promise<RwaDvpCompiledEscrowContract>;
313
+ export declare function inspectDeliveryClaim(sdk: SimplicityClient, input: RwaDvpInspectDeliveryClaimInput): Promise<RwaDvpDeliveryClaimInspection>;
314
+ export declare function executeDeliveryClaim(sdk: SimplicityClient, input: RwaDvpExecuteDeliveryClaimInput): Promise<RwaDvpDeliveryClaimExecution>;
315
+ export declare function inspectRefundClaim(sdk: SimplicityClient, input: RwaDvpInspectRefundClaimInput): Promise<RwaDvpRefundClaimInspection>;
316
+ export declare function executeRefundClaim(sdk: SimplicityClient, input: RwaDvpExecuteRefundClaimInput): Promise<RwaDvpRefundClaimExecution>;
242
317
  export declare function exportEvidence(_sdk: SimplicityClient, input: Omit<RwaDvpEvidenceBundle, "schemaVersion" | "createdAt" | "termsHash" | "policyHash"> & {
243
318
  createdAt?: string | Date;
244
319
  }): RwaDvpEvidenceBundle;