@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
@@ -15,6 +15,7 @@ const summary_1 = require("./summary");
15
15
  const templating_1 = require("./templating");
16
16
  const presets_1 = require("./presets");
17
17
  const toolchain_1 = require("./toolchain");
18
+ const rpc_1 = require("./rpc");
18
19
  const DEFAULT_FEE_SAT = 100;
19
20
  const DEFAULT_SEQUENCE = 4294967293;
20
21
  const DUST_MARGIN_SAT = 600;
@@ -51,6 +52,13 @@ function getArtifactLocktime(artifact) {
51
52
  }
52
53
  return 0;
53
54
  }
55
+ function getEffectiveLocktime(artifact, input) {
56
+ const candidate = input.locktimeHeight;
57
+ if (typeof candidate === "number" && Number.isFinite(candidate) && candidate >= 0) {
58
+ return Math.trunc(candidate);
59
+ }
60
+ return getArtifactLocktime(artifact);
61
+ }
54
62
  function parseSimcWitness(output) {
55
63
  const lines = output
56
64
  .split("\n")
@@ -97,13 +105,15 @@ function chooseUtxo(utxos, minSat, policy) {
97
105
  const unconfirmed = sortCandidates(utxos.filter((utxo) => !utxo.confirmed).filter((utxo) => utxo.sat >= minSat));
98
106
  return unconfirmed[0] ?? null;
99
107
  }
100
- async function findContractUtxosInMempool(elementsCliPath, contractAddress) {
101
- const mempool = await (0, toolchain_1.runCommand)(elementsCliPath, ["getrawmempool"]);
102
- const txids = JSON.parse(mempool.stdout);
108
+ async function callRpc(config, method, params = [], wallet) {
109
+ const client = new rpc_1.ElementsRpcClient(config.rpc);
110
+ return client.call(method, params, wallet);
111
+ }
112
+ async function findContractUtxosInMempool(config, contractAddress) {
113
+ const txids = await callRpc(config, "getrawmempool", []);
103
114
  const matches = [];
104
115
  for (const txid of txids) {
105
- const tx = await (0, toolchain_1.runCommand)(elementsCliPath, ["getrawtransaction", txid, "true"]);
106
- const parsed = JSON.parse(tx.stdout);
116
+ const parsed = await callRpc(config, "getrawtransaction", [txid, true]);
107
117
  for (const output of parsed.vout ?? []) {
108
118
  if (output.scriptPubKey?.address !== contractAddress)
109
119
  continue;
@@ -119,10 +129,8 @@ async function findContractUtxosInMempool(elementsCliPath, contractAddress) {
119
129
  }
120
130
  return matches;
121
131
  }
122
- async function scanUtxosByAddress(elementsCliPath, contractAddress) {
123
- const pattern = `["addr(${contractAddress})"]`;
124
- const result = await (0, toolchain_1.runCommand)(elementsCliPath, ["scantxoutset", "start", pattern]);
125
- const parsed = JSON.parse(result.stdout);
132
+ async function scanUtxosByAddress(config, contractAddress) {
133
+ const parsed = await callRpc(config, "scantxoutset", ["start", [`addr(${contractAddress})`]]);
126
134
  if (!parsed.success || !Array.isArray(parsed.unspents)) {
127
135
  throw new errors_1.ExecutionError("scantxoutset failed", parsed);
128
136
  }
@@ -135,33 +143,29 @@ async function scanUtxosByAddress(elementsCliPath, contractAddress) {
135
143
  height: utxo.height,
136
144
  confirmed: true,
137
145
  }));
138
- const mempool = confirmed.length === 0 ? await findContractUtxosInMempool(elementsCliPath, contractAddress) : [];
146
+ const mempool = confirmed.length === 0 ? await findContractUtxosInMempool(config, contractAddress) : [];
139
147
  return [...confirmed, ...mempool];
140
148
  }
141
- async function decodePsbt(elementsCliPath, psetBase64, wallet) {
142
- const result = await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${wallet}`, "decodepsbt", psetBase64]);
143
- return JSON.parse(result.stdout);
149
+ async function decodePsbt(config, psetBase64, wallet) {
150
+ return callRpc(config, "decodepsbt", [psetBase64], wallet);
144
151
  }
145
- async function getAddressInfo(elementsCliPath, wallet, address) {
146
- const result = await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${wallet}`, "getaddressinfo", address]);
147
- const parsed = JSON.parse(result.stdout);
152
+ async function getAddressInfo(config, wallet, address) {
153
+ const parsed = await callRpc(config, "getaddressinfo", [address], wallet);
148
154
  if (!parsed.scriptPubKey) {
149
155
  throw new errors_1.ExecutionError(`Could not get scriptPubKey from address: ${address}`);
150
156
  }
151
157
  return { scriptPubKey: parsed.scriptPubKey, unconfidential: parsed.unconfidential };
152
158
  }
153
- async function allocateWalletAddress(elementsCliPath, wallet) {
154
- const result = await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${wallet}`, "getnewaddress"]);
155
- const address = result.stdout.trim();
156
- const info = await getAddressInfo(elementsCliPath, wallet, address);
159
+ async function allocateWalletAddress(config, wallet) {
160
+ const address = await callRpc(config, "getnewaddress", [], wallet);
161
+ const info = await getAddressInfo(config, wallet, address);
157
162
  return {
158
163
  address: info.unconfidential ?? address,
159
164
  scriptPubKey: info.scriptPubKey,
160
165
  };
161
166
  }
162
- async function listWalletUtxos(elementsCliPath, wallet) {
163
- const result = await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${wallet}`, "listunspent", "0", "9999999", "[]", "true"]);
164
- const parsed = JSON.parse(result.stdout);
167
+ async function listWalletUtxos(config, wallet) {
168
+ const parsed = await callRpc(config, "listunspent", [0, 9999999, [], true], wallet);
165
169
  return parsed.map((entry) => ({
166
170
  txid: entry.txid,
167
171
  vout: entry.vout,
@@ -233,18 +237,17 @@ function buildPsetSummary(decoded, meta) {
233
237
  fee: decoded.fees ?? decoded.fee ?? null,
234
238
  };
235
239
  }
236
- async function getScriptPubKeyHexFromAddress(elementsCliPath, address) {
237
- const result = await (0, toolchain_1.runCommand)(elementsCliPath, ["getaddressinfo", address]);
238
- const parsed = JSON.parse(result.stdout);
240
+ async function getScriptPubKeyHexFromAddress(config, address, wallet) {
241
+ const parsed = await callRpc(config, "getaddressinfo", [address], wallet);
239
242
  if (!parsed.scriptPubKey) {
240
243
  throw new errors_1.ExecutionError(`Could not get scriptPubKey from address: ${address}`);
241
244
  }
242
245
  return parsed.scriptPubKey.toLowerCase();
243
246
  }
244
- async function assertSummaryPolicy(elementsCliPath, summary, expectedLiquidReceiver) {
247
+ async function assertSummaryPolicy(config, summary, expectedLiquidReceiver, wallet) {
245
248
  if (!expectedLiquidReceiver)
246
249
  return;
247
- const expectedSpk = await getScriptPubKeyHexFromAddress(elementsCliPath, expectedLiquidReceiver);
250
+ const expectedSpk = await getScriptPubKeyHexFromAddress(config, expectedLiquidReceiver, wallet);
248
251
  const normalOutputs = summary.outputs.filter((output) => output.isFee !== true);
249
252
  const found = normalOutputs.some((output) => (output.scriptPubKeyHex ?? "").toLowerCase() === expectedSpk);
250
253
  if (!found) {
@@ -256,14 +259,13 @@ async function assertSummaryPolicy(elementsCliPath, summary, expectedLiquidRecei
256
259
  }
257
260
  }
258
261
  async function buildExecutionState(config, artifact, input) {
259
- const elementsCliPath = config.toolchain.elementsCliPath ?? "eltc";
260
- await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${input.wallet}`, "getwalletinfo"]);
262
+ await callRpc(config, "getwalletinfo", [], input.wallet);
261
263
  const feeSat = input.feeSat ?? config.defaults?.feeSat ?? DEFAULT_FEE_SAT;
262
264
  const minSat = feeSat + DUST_MARGIN_SAT;
263
265
  const utxoPolicy = input.utxoPolicy ?? config.defaults?.utxoPolicy ?? "smallest_over";
264
- const recipientInfo = await getAddressInfo(elementsCliPath, input.wallet, input.toAddress);
266
+ const recipientInfo = await getAddressInfo(config, input.wallet, input.toAddress);
265
267
  const recipientAddress = recipientInfo.unconfidential ?? input.toAddress;
266
- const utxos = await scanUtxosByAddress(elementsCliPath, artifact.compiled.contractAddress);
268
+ const utxos = await scanUtxosByAddress(config, artifact.compiled.contractAddress);
267
269
  const contractUtxo = chooseUtxo(utxos, minSat, utxoPolicy);
268
270
  if (!contractUtxo) {
269
271
  throw new errors_1.UtxoNotFoundError(`No contract UTXO found for address=${artifact.compiled.contractAddress} satisfying minSat=${minSat}`);
@@ -278,29 +280,24 @@ async function buildExecutionState(config, artifact, input) {
278
280
  sendSat,
279
281
  });
280
282
  }
281
- const inputsJson = JSON.stringify([
283
+ const inputsJson = [
282
284
  {
283
285
  txid: contractUtxo.txid,
284
286
  vout: contractUtxo.vout,
285
287
  sequence: input.sequence ?? DEFAULT_SEQUENCE,
286
288
  },
287
- ]);
288
- const outputsJson = JSON.stringify([{ [recipientAddress]: satToBtcNumber(sendSat) }, { fee: satToBtcNumber(feeSat) }]);
289
- const pset1 = await (0, toolchain_1.runCommand)(elementsCliPath, [
290
- "createpsbt",
291
- inputsJson,
292
- outputsJson,
293
- String(getArtifactLocktime(artifact)),
294
- "true",
295
- ]);
296
- const psetUpdated = await (0, toolchain_1.runCommand)(elementsCliPath, ["utxoupdatepsbt", pset1.stdout]);
289
+ ];
290
+ const outputsJson = [{ [recipientAddress]: satToBtcNumber(sendSat) }, { fee: satToBtcNumber(feeSat) }];
291
+ const locktime = getEffectiveLocktime(artifact, input);
292
+ const pset1 = await callRpc(config, "createpsbt", [inputsJson, outputsJson, locktime, true], input.wallet);
293
+ const psetUpdated = await callRpc(config, "utxoupdatepsbt", [pset1], input.wallet);
297
294
  const utxoSpec = `${contractUtxo.scriptPubKey}:${contractUtxo.asset}:${satToBtcStringFromNumber(contractUtxo.sat)}`;
298
- const updateJson = (await (0, toolchain_1.runHalUpdateInput)(config.toolchain.halSimplicityPath, psetUpdated.stdout, 0, utxoSpec, artifact.compiled.cmr, artifact.compiled.internalKey));
295
+ const updateJson = (await (0, toolchain_1.runHalUpdateInput)(config.toolchain.halSimplicityPath, psetUpdated, 0, utxoSpec, artifact.compiled.cmr, artifact.compiled.internalKey));
299
296
  const pset2 = updateJson.pset;
300
297
  if (!pset2) {
301
298
  throw new errors_1.ExecutionError("update-input did not return a pset", updateJson);
302
299
  }
303
- const decoded = await decodePsbt(elementsCliPath, pset2, input.wallet);
300
+ const decoded = await decodePsbt(config, pset2, input.wallet);
304
301
  const summary = buildPsetSummary(decoded, {
305
302
  network: artifact.network,
306
303
  purpose: input.purpose ?? "sdk_execute",
@@ -321,7 +318,7 @@ async function buildExecutionState(config, artifact, input) {
321
318
  cmr: artifact.compiled.cmr,
322
319
  internalKey: artifact.compiled.internalKey,
323
320
  program: artifact.compiled.program,
324
- minHeight: getArtifactLocktime(artifact) || undefined,
321
+ minHeight: locktime || undefined,
325
322
  });
326
323
  const { canonicalJson: summaryCanonicalJson, hash: summaryHash } = (0, summary_1.summarize)(summary);
327
324
  return {
@@ -347,9 +344,8 @@ async function inspectContractCall(config, artifact, input) {
347
344
  };
348
345
  }
349
346
  async function executeContractCall(config, artifact, input) {
350
- const elementsCliPath = config.toolchain.elementsCliPath ?? "eltc";
351
347
  const state = await buildExecutionState(config, artifact, input);
352
- await assertSummaryPolicy(elementsCliPath, state.summary, input.expectedLiquidReceiver);
348
+ await assertSummaryPolicy(config, state.summary, input.expectedLiquidReceiver, input.wallet);
353
349
  const finalizedPset = await signContractInput(config, artifact, state.pset2, input.signer.privkeyHex, input.witness);
354
350
  const finalized = { pset: finalizedPset };
355
351
  if (!finalized.pset) {
@@ -358,13 +354,11 @@ async function executeContractCall(config, artifact, input) {
358
354
  const rawTxHex = normalizeRawTx(await (0, toolchain_1.runHalExtract)(config.toolchain.halSimplicityPath, finalized.pset));
359
355
  let txId;
360
356
  if (input.broadcast) {
361
- const mempool = await (0, toolchain_1.runCommand)(elementsCliPath, ["testmempoolaccept", `["${rawTxHex}"]`]);
362
- const mempoolParsed = JSON.parse(mempool.stdout);
357
+ const mempoolParsed = await callRpc(config, "testmempoolaccept", [[rawTxHex]], input.wallet);
363
358
  if (!Array.isArray(mempoolParsed) || mempoolParsed[0]?.allowed !== true) {
364
359
  throw new errors_1.ExecutionError("testmempoolaccept rejected transaction", mempoolParsed);
365
360
  }
366
- const sendTx = await (0, toolchain_1.runCommand)(elementsCliPath, ["sendrawtransaction", rawTxHex]);
367
- txId = sendTx.stdout.trim();
361
+ txId = await callRpc(config, "sendrawtransaction", [rawTxHex], input.wallet);
368
362
  }
369
363
  return {
370
364
  mode: "execute",
@@ -379,21 +373,19 @@ async function executeContractCall(config, artifact, input) {
379
373
  };
380
374
  }
381
375
  async function findContractUtxos(config, artifact) {
382
- const elementsCliPath = config.toolchain.elementsCliPath ?? "eltc";
383
- return scanUtxosByAddress(elementsCliPath, artifact.compiled.contractAddress);
376
+ return scanUtxosByAddress(config, artifact.compiled.contractAddress);
384
377
  }
385
378
  async function executeGaslessContractCall(config, artifact, input) {
386
379
  if (input.relayer) {
387
380
  return executeRelayedGaslessContractCall(config, artifact, input, input.relayer);
388
381
  }
389
- const elementsCliPath = config.toolchain.elementsCliPath ?? "eltc";
390
382
  const wallet = input.wallet ?? config.rpc.wallet ?? "simplicity-test";
391
383
  if (!input.sponsorWallet) {
392
384
  throw new errors_1.ValidationError("sponsorWallet is required when relayer is not provided");
393
385
  }
394
- await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${wallet}`, "getwalletinfo"]);
395
- await (0, toolchain_1.runCommand)(elementsCliPath, [`-rpcwallet=${input.sponsorWallet}`, "getwalletinfo"]);
396
- const contractUtxos = await scanUtxosByAddress(elementsCliPath, artifact.compiled.contractAddress);
386
+ await callRpc(config, "getwalletinfo", [], wallet);
387
+ await callRpc(config, "getwalletinfo", [], input.sponsorWallet);
388
+ const contractUtxos = await scanUtxosByAddress(config, artifact.compiled.contractAddress);
397
389
  const contractUtxo = chooseUtxo(contractUtxos, input.sendAmount ? Math.round(input.sendAmount * 1e8) : 1, input.utxoPolicy ?? config.defaults?.utxoPolicy ?? "smallest_over");
398
390
  if (!contractUtxo) {
399
391
  throw new errors_1.UtxoNotFoundError(`No contract UTXO found for address=${artifact.compiled.contractAddress}`);
@@ -410,11 +402,11 @@ async function executeGaslessContractCall(config, artifact, input) {
410
402
  if (!input.contractChangeAddress) {
411
403
  throw new errors_1.ValidationError("contractChangeAddress is required when sendAmount is smaller than the contract UTXO");
412
404
  }
413
- const changeInfo = await getAddressInfo(elementsCliPath, wallet, input.contractChangeAddress);
405
+ const changeInfo = await getAddressInfo(config, wallet, input.contractChangeAddress);
414
406
  contractChangeAddress = changeInfo.unconfidential ?? input.contractChangeAddress;
415
407
  contractChangeScriptPubKey = changeInfo.scriptPubKey;
416
408
  }
417
- const sponsorUtxos = await listWalletUtxos(elementsCliPath, input.sponsorWallet);
409
+ const sponsorUtxos = await listWalletUtxos(config, input.sponsorWallet);
418
410
  const sponsorInput = chooseSponsorUtxo(sponsorUtxos, feeSat);
419
411
  if (!sponsorInput) {
420
412
  throw new errors_1.UtxoNotFoundError(`No sponsor UTXO found in wallet=${input.sponsorWallet} for feeSat=${feeSat}`);
@@ -424,17 +416,17 @@ async function executeGaslessContractCall(config, artifact, input) {
424
416
  let sponsorChangeScriptPubKey;
425
417
  if (sponsorChangeSat > 0) {
426
418
  if (input.sponsorChangeAddress) {
427
- const info = await getAddressInfo(elementsCliPath, input.sponsorWallet, input.sponsorChangeAddress);
419
+ const info = await getAddressInfo(config, input.sponsorWallet, input.sponsorChangeAddress);
428
420
  sponsorChangeAddress = info.unconfidential ?? input.sponsorChangeAddress;
429
421
  sponsorChangeScriptPubKey = info.scriptPubKey;
430
422
  }
431
423
  else {
432
- const allocated = await allocateWalletAddress(elementsCliPath, input.sponsorWallet);
424
+ const allocated = await allocateWalletAddress(config, input.sponsorWallet);
433
425
  sponsorChangeAddress = allocated.address;
434
426
  sponsorChangeScriptPubKey = allocated.scriptPubKey;
435
427
  }
436
428
  }
437
- const recipientInfo = await getAddressInfo(elementsCliPath, wallet, input.toAddress);
429
+ const recipientInfo = await getAddressInfo(config, wallet, input.toAddress);
438
430
  const recipientAddress = recipientInfo.unconfidential ?? input.toAddress;
439
431
  const outputs = [{ [recipientAddress]: satToBtcNumber(sendSat) }];
440
432
  if (contractChangeSat > 0 && contractChangeAddress) {
@@ -444,25 +436,19 @@ async function executeGaslessContractCall(config, artifact, input) {
444
436
  outputs.push({ [sponsorChangeAddress]: satToBtcNumber(sponsorChangeSat) });
445
437
  }
446
438
  outputs.push({ fee: satToBtcNumber(feeSat) });
447
- const inputsJson = JSON.stringify([
439
+ const inputsJson = [
448
440
  { txid: contractUtxo.txid, vout: contractUtxo.vout, sequence: DEFAULT_SEQUENCE },
449
441
  { txid: sponsorInput.txid, vout: sponsorInput.vout, sequence: DEFAULT_SEQUENCE },
450
- ]);
451
- const outputsJson = JSON.stringify(outputs);
452
- const pset1 = await (0, toolchain_1.runCommand)(elementsCliPath, [
453
- "createpsbt",
454
- inputsJson,
455
- outputsJson,
456
- String(getArtifactLocktime(artifact)),
457
- "true",
458
- ]);
459
- const psetUpdated = await (0, toolchain_1.runCommand)(elementsCliPath, ["utxoupdatepsbt", pset1.stdout]);
442
+ ];
443
+ const locktime = getEffectiveLocktime(artifact, input);
444
+ const pset1 = await callRpc(config, "createpsbt", [inputsJson, outputs, locktime, true], wallet);
445
+ const psetUpdated = await callRpc(config, "utxoupdatepsbt", [pset1], wallet);
460
446
  const contractSpec = `${contractUtxo.scriptPubKey}:${contractUtxo.asset}:${satToBtcStringFromNumber(contractUtxo.sat)}`;
461
- const contractUpdated = (await (0, toolchain_1.runHalUpdateInput)(config.toolchain.halSimplicityPath, psetUpdated.stdout, 0, contractSpec, artifact.compiled.cmr, artifact.compiled.internalKey));
447
+ const contractUpdated = (await (0, toolchain_1.runHalUpdateInput)(config.toolchain.halSimplicityPath, psetUpdated, 0, contractSpec, artifact.compiled.cmr, artifact.compiled.internalKey));
462
448
  if (!contractUpdated.pset) {
463
449
  throw new errors_1.ExecutionError("update-input did not return a pset", contractUpdated);
464
450
  }
465
- const decoded = await decodePsbt(elementsCliPath, contractUpdated.pset, input.sponsorWallet);
451
+ const decoded = await decodePsbt(config, contractUpdated.pset, input.sponsorWallet);
466
452
  const summary = buildPsetSummary(decoded, {
467
453
  network: artifact.network,
468
454
  purpose: "sdk_gasless_execute",
@@ -481,37 +467,26 @@ async function executeGaslessContractCall(config, artifact, input) {
481
467
  cmr: artifact.compiled.cmr,
482
468
  internalKey: artifact.compiled.internalKey,
483
469
  program: artifact.compiled.program,
484
- minHeight: getArtifactLocktime(artifact) || undefined,
470
+ minHeight: locktime || undefined,
485
471
  expectedLiquidReceiver: recipientAddress,
486
472
  });
487
473
  const { canonicalJson: summaryCanonicalJson, hash: summaryHash } = (0, summary_1.summarize)(summary);
488
474
  const contractSignedPset = await signContractInput(config, artifact, contractUpdated.pset, input.signer.privkeyHex, input.witness);
489
- const sponsorSigned = await (0, toolchain_1.runCommand)(elementsCliPath, [
490
- `-rpcwallet=${input.sponsorWallet}`,
491
- "walletprocesspsbt",
492
- contractSignedPset,
493
- "true",
494
- "ALL",
495
- "true",
496
- ]);
497
- const sponsorSignedParsed = JSON.parse(sponsorSigned.stdout);
475
+ const sponsorSignedParsed = await callRpc(config, "walletprocesspsbt", [contractSignedPset, true, "ALL", true], input.sponsorWallet);
498
476
  if (!sponsorSignedParsed.psbt) {
499
477
  throw new errors_1.ExecutionError("walletprocesspsbt did not return a sponsor-signed pset", sponsorSignedParsed);
500
478
  }
501
- const finalized = await (0, toolchain_1.runCommand)(elementsCliPath, ["finalizepsbt", sponsorSignedParsed.psbt, "true"]);
502
- const finalizedParsed = JSON.parse(finalized.stdout);
479
+ const finalizedParsed = await callRpc(config, "finalizepsbt", [sponsorSignedParsed.psbt, true]);
503
480
  if (!finalizedParsed.complete || !finalizedParsed.hex) {
504
481
  throw new errors_1.ExecutionError("PSET was not complete after sponsor signing", finalizedParsed);
505
482
  }
506
483
  let txId;
507
484
  if (input.broadcast) {
508
- const mempool = await (0, toolchain_1.runCommand)(elementsCliPath, ["testmempoolaccept", `[\"${finalizedParsed.hex}\"]`]);
509
- const mempoolParsed = JSON.parse(mempool.stdout);
485
+ const mempoolParsed = await callRpc(config, "testmempoolaccept", [[finalizedParsed.hex]], input.sponsorWallet);
510
486
  if (!Array.isArray(mempoolParsed) || mempoolParsed[0]?.allowed !== true) {
511
487
  throw new errors_1.ExecutionError("testmempoolaccept rejected transaction", mempoolParsed);
512
488
  }
513
- const sent = await (0, toolchain_1.runCommand)(elementsCliPath, ["sendrawtransaction", finalizedParsed.hex]);
514
- txId = sent.stdout.trim();
489
+ txId = await callRpc(config, "sendrawtransaction", [finalizedParsed.hex], input.sponsorWallet);
515
490
  }
516
491
  return {
517
492
  mode: "gasless-execute",
@@ -0,0 +1,61 @@
1
+ import type { SimplicityClient } from "../client/SimplicityClient";
2
+ import type { BondOutputBindingMode, OutputBindingSupportEvaluation, OutputBindingSupportMatrix, OutputBindingReasonCode, OutputBindingSupportedForm, OutputForm, OutputRawFields } from "./types";
3
+ export declare const OUTPUT_BINDING_SUPPORT_MATRIX: OutputBindingSupportMatrix;
4
+ export declare function describeOutputBindingSupport(): OutputBindingSupportMatrix;
5
+ export declare function normalizeOutputForm(input?: Partial<OutputForm>): OutputForm;
6
+ interface ResolvedOutputRawFields {
7
+ assetBytesHex: string;
8
+ amountBytesHex: string;
9
+ nonceBytesHex: string;
10
+ scriptPubKeyHashHex: string;
11
+ rangeProofHashHex: string;
12
+ scriptComponentSource: "raw-bytes" | "hash";
13
+ rangeProofComponentSource: "raw-bytes" | "hash";
14
+ }
15
+ export declare function normalizeOutputRawFields(input?: Partial<OutputRawFields>): Partial<OutputRawFields> | undefined;
16
+ export declare function analyzeOutputRawFields(input?: Partial<OutputRawFields>): {
17
+ provided: boolean;
18
+ complete: boolean;
19
+ valid: boolean;
20
+ normalized?: ResolvedOutputRawFields;
21
+ missingFields: string[];
22
+ invalidFields: string[];
23
+ };
24
+ export declare function isExplicitV1OutputForm(input: OutputForm): boolean;
25
+ export declare function isExplicitAssetInputSupported(assetId: string): boolean;
26
+ export declare function resolveOutputBindingMode(requested: BondOutputBindingMode | undefined, nextOutputHash: string | undefined, nextOutputScriptHash: string | undefined): BondOutputBindingMode;
27
+ export declare function hashHexBytes(hex: string): string;
28
+ export declare function computeExplicitV1OutputHash(input: {
29
+ assetHex: string;
30
+ nextAmountSat: number;
31
+ nextOutputScriptHash: string;
32
+ }): string;
33
+ export declare function computeRawOutputV1Hash(input: Partial<OutputRawFields>): string;
34
+ export declare function getScriptPubKeyHexViaRpc(sdk: SimplicityClient, address: string): Promise<string>;
35
+ export declare function resolveExplicitAssetHex(sdk: SimplicityClient, assetId: string): Promise<string | undefined>;
36
+ export declare function resolveOutputBindingDecision(input: {
37
+ requestedBindingMode?: BondOutputBindingMode;
38
+ nextOutputHash?: string;
39
+ nextOutputScriptHash?: string;
40
+ autoDerivedNextOutputHash?: boolean;
41
+ explicitAssetSupported: boolean;
42
+ outputForm?: Partial<OutputForm>;
43
+ rawOutput?: Partial<OutputRawFields>;
44
+ }): {
45
+ requestedBindingMode: BondOutputBindingMode;
46
+ outputBindingMode: BondOutputBindingMode;
47
+ supportedForm: OutputBindingSupportedForm;
48
+ reasonCode: OutputBindingReasonCode;
49
+ autoDerived: boolean;
50
+ fallbackReason?: string;
51
+ outputForm: OutputForm;
52
+ };
53
+ export declare function evaluateOutputBindingSupport(input: {
54
+ assetId: string;
55
+ requestedBindingMode?: BondOutputBindingMode;
56
+ outputForm?: Partial<OutputForm>;
57
+ rawOutput?: Partial<OutputRawFields>;
58
+ nextOutputHash?: string;
59
+ nextOutputScriptAvailable?: boolean;
60
+ }): OutputBindingSupportEvaluation;
61
+ export {};