@hazbase/simplicity 0.4.4 → 0.4.6

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 CHANGED
@@ -184,6 +184,16 @@ custom RWA asset, policy position, vault output, expiry, and summary hash into
184
184
  the `X-PAYMENT` payload, and rejects proposals that still require holder-side
185
185
  Simplicity witness construction.
186
186
 
187
+ Services can prepare that policy-spend proposal with
188
+ `sdk.policies.inspectTransfer(...)` or `sdk.policies.executeTransfer(...)`.
189
+ When the current policy state carries a custom Liquid asset id, the policy
190
+ executor automatically uses the SDK multi-asset PSET path instead of the legacy
191
+ L-BTC-only spend path. Pass `extraInputs` for the L-BTC fee/sponsor inputs and
192
+ `contractInput` when the policy position UTXO should be selected by outpoint,
193
+ asset id, amount, blinding data, or sequence. If the policy UTXO amount is not
194
+ fully transferred, pass an explicit `changeAddress`; exact-position redemptions
195
+ do not need one.
196
+
187
197
  Typical entrypoints:
188
198
  - `sdk.rwaDvp.definePurchase(...)`
189
199
  - `sdk.rwaDvp.buildPaymentRequirements(...)`
@@ -232,6 +242,13 @@ These helpers model a Liquidex-style exchange:
232
242
  - the resulting `X-PAYMENT` payload commits to both the payment output and the
233
243
  delivery output through a summary hash
234
244
 
245
+ When the delivered RWA output must go to a policy/Simplicity address instead of
246
+ the taker's normal wallet receive address, pass `takerDeliveryAddress` (or the
247
+ `deliveryAddress` alias) to `prepareLiquidAtomicDvpLwkWasmTakerPayment(...)`.
248
+ The loaded LWK module must expose a recipient-aware `liquidexTake` variant; if
249
+ it does not, the SDK fails explicitly instead of silently creating a PSET that
250
+ delivers to the wrong address.
251
+
235
252
  The LWK convenience helpers dynamically load `lwk_node` or `lwk_wasm` from the
236
253
  consuming application. Install one of them in the application that prepares or
237
254
  takes proposals:
@@ -429,7 +429,7 @@ async function findContractUtxos(config, artifact) {
429
429
  return scanUtxosByAddress(config, artifact.compiled.contractAddress);
430
430
  }
431
431
  function findRequestedContractUtxo(utxos, input) {
432
- if (!input)
432
+ if (!input?.txid)
433
433
  return null;
434
434
  const requested = utxos.find((utxo) => (utxo.txid === input.txid
435
435
  && (input.vout === undefined || utxo.vout === input.vout))) ?? null;
@@ -441,6 +441,28 @@ function findRequestedContractUtxo(utxos, input) {
441
441
  sat: input.amountSat ?? requested.sat,
442
442
  };
443
443
  }
444
+ function filterContractUtxosByRequestedAsset(utxos, input) {
445
+ if (!input)
446
+ return utxos;
447
+ return utxos.filter((utxo) => {
448
+ const matchesRequestedOutpoint = Boolean(input.txid
449
+ && utxo.txid === input.txid
450
+ && (input.vout === undefined || utxo.vout === input.vout));
451
+ if (input.txid && utxo.txid !== input.txid)
452
+ return false;
453
+ if (input.vout !== undefined && utxo.vout !== input.vout)
454
+ return false;
455
+ if (input.asset) {
456
+ if (!utxo.asset)
457
+ return matchesRequestedOutpoint;
458
+ if (normalizeAssetId(utxo.asset) !== normalizeAssetId(input.asset))
459
+ return false;
460
+ }
461
+ if (input.amountSat !== undefined && utxo.sat !== input.amountSat)
462
+ return false;
463
+ return true;
464
+ });
465
+ }
444
466
  function buildMultiAssetBlindingSecrets(input) {
445
467
  const secrets = [];
446
468
  if (input.contractInput?.rawTxHex && input.contractInput.blindingPrivateKey) {
@@ -472,9 +494,15 @@ async function buildMultiAssetExecutionState(config, artifact, input) {
472
494
  const contractUtxos = await scanUtxosByAddress(config, artifact.compiled.contractAddress);
473
495
  const feeSat = input.feeSat ?? config.defaults?.feeSat ?? DEFAULT_FEE_SAT;
474
496
  const requested = findRequestedContractUtxo(contractUtxos, input.contractInput);
475
- const contractUtxo = requested ?? chooseUtxo(contractUtxos, 1, config.defaults?.utxoPolicy ?? "smallest_over");
497
+ const candidateContractUtxos = filterContractUtxosByRequestedAsset(contractUtxos, input.contractInput);
498
+ const contractUtxo = requested ?? chooseUtxo(candidateContractUtxos, 1, config.defaults?.utxoPolicy ?? "smallest_over");
476
499
  if (!contractUtxo) {
477
- throw new errors_1.UtxoNotFoundError(`No contract UTXO found for address=${artifact.compiled.contractAddress}`);
500
+ throw new errors_1.UtxoNotFoundError(`No contract UTXO found for address=${artifact.compiled.contractAddress}`, {
501
+ requestedAsset: input.contractInput?.asset,
502
+ requestedAmountSat: input.contractInput?.amountSat,
503
+ requestedTxid: input.contractInput?.txid,
504
+ requestedVout: input.contractInput?.vout,
505
+ });
478
506
  }
479
507
  const extraInputs = input.extraInputs ?? [];
480
508
  const inputTotals = new Map();
@@ -521,7 +549,7 @@ async function buildMultiAssetExecutionState(config, artifact, input) {
521
549
  {
522
550
  txid: contractUtxo.txid,
523
551
  vout: contractUtxo.vout,
524
- sequence: input.locktimeHeight ? DEFAULT_SEQUENCE : DEFAULT_SEQUENCE,
552
+ sequence: input.contractInput?.sequence ?? DEFAULT_SEQUENCE,
525
553
  },
526
554
  ...extraInputs.map((extra) => ({
527
555
  txid: extra.txid,
@@ -332,10 +332,11 @@ export interface MultiAssetContractCallInput {
332
332
  signer: SignerConfig;
333
333
  witness?: WitnessConfig;
334
334
  contractInput?: {
335
- txid: string;
335
+ txid?: string;
336
336
  vout?: number;
337
337
  asset?: string;
338
338
  amountSat?: number;
339
+ sequence?: number;
339
340
  rawTxHex?: string;
340
341
  blindingPrivateKey?: string;
341
342
  };
@@ -1,5 +1,5 @@
1
1
  import type { SimplicityClient } from "../client/SimplicityClient";
2
- import type { BondOutputBindingMode, OutputRawFields, PolicyOutputAmountForm, PolicyOutputAssetForm, PolicyEvidenceBundle, PolicyEvidenceBundleSchemaVersion, PolicyOutputBindingReasonCode, PolicyOutputBindingSupportedForm, PolicyOutputDescriptor, PolicyOutputNonceForm, PolicyReceiver, PolicyOutputRangeProofForm, PolicyState, PolicyTemplateDocument, PolicyTemplateManifest, PolicyTemplateManifestValidationResult, PolicyTemplateManifestVersion, PolicyTemplateInput, PolicyTransferDescriptor, PolicyVerificationReportSchemaVersion, PropagationMode, SimplicityArtifact } from "../core/types";
2
+ import type { BondOutputBindingMode, OutputRawFields, PolicyOutputAmountForm, PolicyOutputAssetForm, PolicyEvidenceBundle, PolicyEvidenceBundleSchemaVersion, PolicyOutputBindingReasonCode, PolicyOutputBindingSupportedForm, PolicyOutputDescriptor, PolicyOutputNonceForm, PolicyReceiver, PolicyOutputRangeProofForm, PolicyState, PolicyTemplateDocument, PolicyTemplateManifest, PolicyTemplateManifestValidationResult, PolicyTemplateManifestVersion, PolicyTemplateInput, PolicyTransferDescriptor, PolicyVerificationReportSchemaVersion, PropagationMode, MultiAssetContractCallInput, MultiAssetContractInput, SimplicityArtifact } from "../core/types";
3
3
  export declare const POLICY_TEMPLATE_MANIFEST_SCHEMA_VERSION: PolicyTemplateManifestVersion;
4
4
  export declare const POLICY_VERIFICATION_REPORT_SCHEMA_VERSION: PolicyVerificationReportSchemaVersion;
5
5
  export declare const POLICY_EVIDENCE_BUNDLE_SCHEMA_VERSION: PolicyEvidenceBundleSchemaVersion;
@@ -576,6 +576,10 @@ export declare function executeDirectTransfer(sdk: SimplicityClient, input: {
576
576
  broadcast?: boolean;
577
577
  feeSat?: number;
578
578
  utxoPolicy?: "smallest_over" | "largest" | "newest";
579
+ contractInput?: MultiAssetContractCallInput["contractInput"];
580
+ extraInputs?: MultiAssetContractInput[];
581
+ changeAddress?: string;
582
+ useMultiAssetExecutor?: boolean;
579
583
  }): Promise<{
580
584
  mode: "direct-hop";
581
585
  prepared: {
@@ -912,6 +916,10 @@ export declare function executeTransfer(sdk: SimplicityClient, input: {
912
916
  broadcast?: boolean;
913
917
  feeSat?: number;
914
918
  utxoPolicy?: "smallest_over" | "largest" | "newest";
919
+ contractInput?: MultiAssetContractCallInput["contractInput"];
920
+ extraInputs?: MultiAssetContractInput[];
921
+ changeAddress?: string;
922
+ useMultiAssetExecutor?: boolean;
915
923
  }): Promise<{
916
924
  mode: "plain-exit";
917
925
  prepared: {
@@ -33,6 +33,7 @@ const node_fs_1 = require("node:fs");
33
33
  const node_path_1 = __importDefault(require("node:path"));
34
34
  const summary_1 = require("../core/summary");
35
35
  const errors_1 = require("../core/errors");
36
+ const executor_1 = require("../core/executor");
36
37
  const outputBinding_1 = require("../core/outputBinding");
37
38
  const reporting_1 = require("../core/reporting");
38
39
  function resolvePolicyDocsAsset(filename) {
@@ -602,6 +603,53 @@ function buildPolicyRecursiveWitness(prepared) {
602
603
  },
603
604
  };
604
605
  }
606
+ function isBitcoinPolicyAsset(assetId) {
607
+ return assetId.trim().toLowerCase() === "bitcoin";
608
+ }
609
+ function shouldUseMultiAssetPolicyExecutor(assetId, input) {
610
+ if (input.useMultiAssetExecutor === true)
611
+ return true;
612
+ if (!isBitcoinPolicyAsset(assetId))
613
+ return true;
614
+ if (input.contractInput?.asset)
615
+ return true;
616
+ if ((input.extraInputs?.length ?? 0) > 0)
617
+ return true;
618
+ return Boolean(input.changeAddress);
619
+ }
620
+ function buildPolicyMultiAssetCallInput(input) {
621
+ const contractAmountSat = input.contractInput?.amountSat ?? input.currentState.amountSat;
622
+ if (contractAmountSat !== input.outputAmountSat && !input.changeAddress) {
623
+ throw new errors_1.ValidationError("changeAddress is required when policy contract input amount differs from the transfer output amount", {
624
+ contractAmountSat,
625
+ outputAmountSat: input.outputAmountSat,
626
+ assetId: input.currentState.assetId,
627
+ });
628
+ }
629
+ return {
630
+ wallet: input.wallet,
631
+ signer: input.signer,
632
+ contractInput: {
633
+ ...(input.contractInput ?? {}),
634
+ asset: input.contractInput?.asset ?? input.currentState.assetId,
635
+ amountSat: contractAmountSat,
636
+ sequence: input.contractInput?.sequence ?? input.contractSequence,
637
+ },
638
+ ...(input.extraInputs ? { extraInputs: input.extraInputs } : {}),
639
+ outputs: [
640
+ {
641
+ address: input.outputAddress,
642
+ asset: input.currentState.assetId,
643
+ amountSat: input.outputAmountSat,
644
+ },
645
+ ],
646
+ feeSat: input.feeSat,
647
+ ...(input.changeAddress ? { changeAddress: input.changeAddress } : {}),
648
+ purpose: input.purpose,
649
+ ...(input.broadcast !== undefined ? { broadcast: input.broadcast } : {}),
650
+ witness: input.witness,
651
+ };
652
+ }
605
653
  function camelToUpperSnake(value) {
606
654
  return value
607
655
  .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
@@ -1396,6 +1444,24 @@ async function inspectDirectTransfer(sdk, input) {
1396
1444
  });
1397
1445
  }
1398
1446
  const currentContract = sdk.fromArtifact(currentArtifact);
1447
+ const currentState = prepared.current.stateValue;
1448
+ const directWitness = buildPolicyDirectWitness(prepared);
1449
+ if (shouldUseMultiAssetPolicyExecutor(currentState.assetId, input)) {
1450
+ const inspect = await (0, executor_1.inspectMultiAssetContractCall)(sdk.config, currentArtifact, buildPolicyMultiAssetCallInput({
1451
+ ...input,
1452
+ currentState,
1453
+ outputAddress: prepared.nextCompiled.contractAddress,
1454
+ outputAmountSat: input.nextAmountSat,
1455
+ contractSequence: resolvePolicySequence(currentState),
1456
+ witness: directWitness,
1457
+ purpose: "sdk_policy_direct_transfer",
1458
+ }));
1459
+ return {
1460
+ mode: "direct-hop",
1461
+ prepared,
1462
+ inspect,
1463
+ };
1464
+ }
1399
1465
  const inspect = await currentContract.inspectCall({
1400
1466
  wallet: input.wallet,
1401
1467
  toAddress: prepared.nextCompiled.contractAddress,
@@ -1403,8 +1469,8 @@ async function inspectDirectTransfer(sdk, input) {
1403
1469
  sendAmount: satToBtcAmount(input.nextAmountSat),
1404
1470
  feeSat: input.feeSat,
1405
1471
  utxoPolicy: input.utxoPolicy,
1406
- sequence: resolvePolicySequence(prepared.current.stateValue),
1407
- witness: buildPolicyDirectWitness(prepared),
1472
+ sequence: resolvePolicySequence(currentState),
1473
+ witness: directWitness,
1408
1474
  });
1409
1475
  return {
1410
1476
  mode: "direct-hop",
@@ -1422,6 +1488,24 @@ async function executeDirectTransfer(sdk, input) {
1422
1488
  });
1423
1489
  }
1424
1490
  const currentContract = sdk.fromArtifact(currentArtifact);
1491
+ const currentState = prepared.current.stateValue;
1492
+ const directWitness = buildPolicyDirectWitness(prepared);
1493
+ if (shouldUseMultiAssetPolicyExecutor(currentState.assetId, input)) {
1494
+ const execution = await (0, executor_1.executeMultiAssetContractCall)(sdk.config, currentArtifact, buildPolicyMultiAssetCallInput({
1495
+ ...input,
1496
+ currentState,
1497
+ outputAddress: prepared.nextCompiled.contractAddress,
1498
+ outputAmountSat: input.nextAmountSat,
1499
+ contractSequence: resolvePolicySequence(currentState),
1500
+ witness: directWitness,
1501
+ purpose: "sdk_policy_direct_transfer",
1502
+ }));
1503
+ return {
1504
+ mode: "direct-hop",
1505
+ prepared,
1506
+ execution,
1507
+ };
1508
+ }
1425
1509
  const execution = await currentContract.execute({
1426
1510
  wallet: input.wallet,
1427
1511
  toAddress: prepared.nextCompiled.contractAddress,
@@ -1430,8 +1514,8 @@ async function executeDirectTransfer(sdk, input) {
1430
1514
  feeSat: input.feeSat,
1431
1515
  broadcast: input.broadcast,
1432
1516
  utxoPolicy: input.utxoPolicy,
1433
- sequence: resolvePolicySequence(prepared.current.stateValue),
1434
- witness: buildPolicyDirectWitness(prepared),
1517
+ sequence: resolvePolicySequence(currentState),
1518
+ witness: directWitness,
1435
1519
  });
1436
1520
  return {
1437
1521
  mode: "direct-hop",
@@ -1500,7 +1584,25 @@ async function inspectTransfer(sdk, input) {
1500
1584
  });
1501
1585
  }
1502
1586
  const currentContract = sdk.fromArtifact(currentArtifact);
1587
+ const currentState = prepared.current.stateValue;
1588
+ const recursiveWitness = buildPolicyRecursiveWitness(prepared);
1503
1589
  if (!prepared.nextCompiled) {
1590
+ if (shouldUseMultiAssetPolicyExecutor(currentState.assetId, input)) {
1591
+ const inspect = await (0, executor_1.inspectMultiAssetContractCall)(sdk.config, currentArtifact, buildPolicyMultiAssetCallInput({
1592
+ ...input,
1593
+ currentState,
1594
+ outputAddress: input.nextReceiver.address,
1595
+ outputAmountSat: input.nextAmountSat,
1596
+ contractSequence: resolvePolicySequence(currentState),
1597
+ witness: recursiveWitness,
1598
+ purpose: "sdk_policy_transfer_plain_exit",
1599
+ }));
1600
+ return {
1601
+ mode: "plain-exit",
1602
+ prepared,
1603
+ inspect,
1604
+ };
1605
+ }
1504
1606
  const inspect = await currentContract.inspectCall({
1505
1607
  wallet: input.wallet,
1506
1608
  toAddress: input.nextReceiver.address,
@@ -1508,8 +1610,8 @@ async function inspectTransfer(sdk, input) {
1508
1610
  sendAmount: satToBtcAmount(input.nextAmountSat),
1509
1611
  feeSat: input.feeSat,
1510
1612
  utxoPolicy: input.utxoPolicy,
1511
- sequence: resolvePolicySequence(prepared.current.stateValue),
1512
- witness: buildPolicyRecursiveWitness(prepared),
1613
+ sequence: resolvePolicySequence(currentState),
1614
+ witness: recursiveWitness,
1513
1615
  });
1514
1616
  return {
1515
1617
  mode: "plain-exit",
@@ -1517,6 +1619,22 @@ async function inspectTransfer(sdk, input) {
1517
1619
  inspect,
1518
1620
  };
1519
1621
  }
1622
+ if (shouldUseMultiAssetPolicyExecutor(currentState.assetId, input)) {
1623
+ const inspect = await (0, executor_1.inspectMultiAssetContractCall)(sdk.config, currentArtifact, buildPolicyMultiAssetCallInput({
1624
+ ...input,
1625
+ currentState,
1626
+ outputAddress: prepared.nextCompiled.contractAddress,
1627
+ outputAmountSat: input.nextAmountSat,
1628
+ contractSequence: resolvePolicySequence(currentState),
1629
+ witness: recursiveWitness,
1630
+ purpose: "sdk_policy_transfer",
1631
+ }));
1632
+ return {
1633
+ mode: prepared.verificationReport.enforcement,
1634
+ prepared,
1635
+ inspect,
1636
+ };
1637
+ }
1520
1638
  const inspect = await currentContract.inspectCall({
1521
1639
  wallet: input.wallet,
1522
1640
  toAddress: prepared.nextCompiled.contractAddress,
@@ -1524,8 +1642,8 @@ async function inspectTransfer(sdk, input) {
1524
1642
  sendAmount: satToBtcAmount(input.nextAmountSat),
1525
1643
  feeSat: input.feeSat,
1526
1644
  utxoPolicy: input.utxoPolicy,
1527
- sequence: resolvePolicySequence(prepared.current.stateValue),
1528
- witness: buildPolicyRecursiveWitness(prepared),
1645
+ sequence: resolvePolicySequence(currentState),
1646
+ witness: recursiveWitness,
1529
1647
  });
1530
1648
  return {
1531
1649
  mode: prepared.verificationReport.enforcement,
@@ -1543,7 +1661,25 @@ async function executeTransfer(sdk, input) {
1543
1661
  });
1544
1662
  }
1545
1663
  const currentContract = sdk.fromArtifact(currentArtifact);
1664
+ const currentState = prepared.current.stateValue;
1665
+ const recursiveWitness = buildPolicyRecursiveWitness(prepared);
1546
1666
  if (!prepared.nextCompiled) {
1667
+ if (shouldUseMultiAssetPolicyExecutor(currentState.assetId, input)) {
1668
+ const execution = await (0, executor_1.executeMultiAssetContractCall)(sdk.config, currentArtifact, buildPolicyMultiAssetCallInput({
1669
+ ...input,
1670
+ currentState,
1671
+ outputAddress: input.nextReceiver.address,
1672
+ outputAmountSat: input.nextAmountSat,
1673
+ contractSequence: resolvePolicySequence(currentState),
1674
+ witness: recursiveWitness,
1675
+ purpose: "sdk_policy_transfer_plain_exit",
1676
+ }));
1677
+ return {
1678
+ mode: "plain-exit",
1679
+ prepared,
1680
+ execution,
1681
+ };
1682
+ }
1547
1683
  const execution = await currentContract.execute({
1548
1684
  wallet: input.wallet,
1549
1685
  toAddress: input.nextReceiver.address,
@@ -1552,8 +1688,8 @@ async function executeTransfer(sdk, input) {
1552
1688
  feeSat: input.feeSat,
1553
1689
  broadcast: input.broadcast,
1554
1690
  utxoPolicy: input.utxoPolicy,
1555
- sequence: resolvePolicySequence(prepared.current.stateValue),
1556
- witness: buildPolicyRecursiveWitness(prepared),
1691
+ sequence: resolvePolicySequence(currentState),
1692
+ witness: recursiveWitness,
1557
1693
  });
1558
1694
  return {
1559
1695
  mode: "plain-exit",
@@ -1561,6 +1697,22 @@ async function executeTransfer(sdk, input) {
1561
1697
  execution,
1562
1698
  };
1563
1699
  }
1700
+ if (shouldUseMultiAssetPolicyExecutor(currentState.assetId, input)) {
1701
+ const execution = await (0, executor_1.executeMultiAssetContractCall)(sdk.config, currentArtifact, buildPolicyMultiAssetCallInput({
1702
+ ...input,
1703
+ currentState,
1704
+ outputAddress: prepared.nextCompiled.contractAddress,
1705
+ outputAmountSat: input.nextAmountSat,
1706
+ contractSequence: resolvePolicySequence(currentState),
1707
+ witness: recursiveWitness,
1708
+ purpose: "sdk_policy_transfer",
1709
+ }));
1710
+ return {
1711
+ mode: prepared.verificationReport.enforcement,
1712
+ prepared,
1713
+ execution,
1714
+ };
1715
+ }
1564
1716
  const execution = await currentContract.execute({
1565
1717
  wallet: input.wallet,
1566
1718
  toAddress: prepared.nextCompiled.contractAddress,
@@ -1569,8 +1721,8 @@ async function executeTransfer(sdk, input) {
1569
1721
  feeSat: input.feeSat,
1570
1722
  broadcast: input.broadcast,
1571
1723
  utxoPolicy: input.utxoPolicy,
1572
- sequence: resolvePolicySequence(prepared.current.stateValue),
1573
- witness: buildPolicyRecursiveWitness(prepared),
1724
+ sequence: resolvePolicySequence(currentState),
1725
+ witness: recursiveWitness,
1574
1726
  });
1575
1727
  return {
1576
1728
  mode: prepared.verificationReport.enforcement,
@@ -137,6 +137,16 @@ export interface LiquidAtomicDvpTakeProposalInput {
137
137
  proposal?: string;
138
138
  proposalPsetBase64?: string;
139
139
  proposalTxHex?: string;
140
+ /**
141
+ * Optional recipient for the maker-delivered asset when the taker PSET is
142
+ * completed. Use this for policy/Simplicity delivery addresses that are not a
143
+ * normal wallet receive address.
144
+ */
145
+ takerDeliveryAddress?: string;
146
+ /**
147
+ * Backwards-friendly alias for `takerDeliveryAddress`.
148
+ */
149
+ deliveryAddress?: string;
140
150
  payer?: string;
141
151
  esploraUrl?: string;
142
152
  waterfalls?: boolean;
@@ -154,6 +164,7 @@ export type LiquidAtomicDvpTakeProposalResult = ReturnType<typeof buildLiquidAto
154
164
  dwid?: string;
155
165
  proposalInput: LiquidAtomicDvpOutputRequirement;
156
166
  proposalOutput: LiquidAtomicDvpOutputRequirement;
167
+ takerDeliveryAddress?: string;
157
168
  };
158
169
  export interface LiquidAtomicDvpVerifyPayloadResult {
159
170
  isValid: boolean;
@@ -113,7 +113,8 @@ async function prepareLiquidAtomicDvpLwkWasmTakerPayment(input) {
113
113
  let builder = network.txBuilder();
114
114
  if (input.feeRate !== undefined)
115
115
  builder = builder.feeRate(input.feeRate);
116
- builder = builder.liquidexTake([validated]);
116
+ const takerDeliveryAddress = normalizeOptionalString(input.takerDeliveryAddress ?? input.deliveryAddress, "takerDeliveryAddress");
117
+ builder = applyLiquidexTake(lwk, builder, [validated], network, takerDeliveryAddress);
117
118
  const unsigned = builder.finish(wollet);
118
119
  const signed = signer.sign(unsigned);
119
120
  const pset = input.finalize === false ? signed : wollet.finalize(signed);
@@ -128,6 +129,7 @@ async function prepareLiquidAtomicDvpLwkWasmTakerPayment(input) {
128
129
  ...(typeof wollet.dwid === "function" ? { dwid: wollet.dwid() } : {}),
129
130
  proposalInput,
130
131
  proposalOutput,
132
+ ...(takerDeliveryAddress ? { takerDeliveryAddress } : {}),
131
133
  };
132
134
  }
133
135
  function buildLiquidAtomicDvpSummaryHash(input) {
@@ -360,6 +362,18 @@ function parseLwkTransaction(lwk, txHex) {
360
362
  return new lwk.Transaction(txHex);
361
363
  throw new Error("LWK Transaction support is required to validate a Liquidex proposal against a transaction.");
362
364
  }
365
+ function applyLiquidexTake(lwk, builder, validatedProposals, network, takerDeliveryAddress) {
366
+ if (!takerDeliveryAddress)
367
+ return builder.liquidexTake(validatedProposals);
368
+ const deliveryAddress = parseLwkAddress(lwk, takerDeliveryAddress, network);
369
+ for (const method of ["liquidexTakeWithRecipient", "liquidexTakeToAddress", "liquidexTakeTo"]) {
370
+ if (typeof builder[method] === "function") {
371
+ return builder[method](validatedProposals, deliveryAddress);
372
+ }
373
+ }
374
+ throw new Error("Liquidex taker delivery address override is not supported by the loaded LWK module. " +
375
+ "Upgrade LWK or use a fixed-recipient/manual atomic DvP PSET builder.");
376
+ }
363
377
  function parseLiquidexProposal(lwk, value) {
364
378
  const encoded = String(value ?? "").trim();
365
379
  if (!encoded)
@@ -435,6 +449,16 @@ function normalizeOutput(value, name) {
435
449
  recipient: requiredString(raw.recipient, `${name}.recipient`),
436
450
  };
437
451
  }
452
+ function normalizeOptionalString(value, name) {
453
+ if (value === undefined || value === null)
454
+ return undefined;
455
+ const text = String(value).trim();
456
+ if (!text)
457
+ return undefined;
458
+ if (text.length > 2048)
459
+ throw new Error(`${name} is too long`);
460
+ return text;
461
+ }
438
462
  function normalizeServiceSigner(value) {
439
463
  if (value === null || value === undefined)
440
464
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hazbase/simplicity",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "An SDK for Simplicity on Liquid",
5
5
  "author": "IndieSquare Inc <info@hazbase.com>",
6
6
  "keywords": [