@hazbase/simplicity 0.2.0 → 0.3.0

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
@@ -19,7 +19,7 @@ With the current public SDK you can build and test:
19
19
  - output binding with public support/fallback reporting
20
20
  - bond redemption / settlement / close-out flows
21
21
  - LP fund capital call / distribution / close-out flows
22
- - receivable repayment-first funding / repayment / closing flows
22
+ - receivable repayment-first funding / partial repayment / closing flows
23
23
  - evidence, trust summary, lineage, and finality exports
24
24
 
25
25
  ## Public Architecture
@@ -130,9 +130,14 @@ Main entrypoints:
130
130
  Representative example:
131
131
  - [show-fund-claim-close-flow.ts](./examples/show-fund-claim-close-flow.ts)
132
132
 
133
+ Operational note:
134
+ - [fund-cutoff-runbook.md](./docs/fund-cutoff-runbook.md)
135
+
133
136
  ### Receivables
134
137
 
135
- Use `sdk.receivables` for repayment-first receivable or invoice-style pilots where you want canonical state transitions, runtime claim descriptors, lineage verification, and terminal closing.
138
+ Use `sdk.receivables` for repayment-first receivable or invoice-style pilots where you want canonical state transitions, role-aware runtime claim descriptors, partial repayment handling, lineage verification, and terminal closing.
139
+
140
+ By default, funding claims resolve against the originator claimant key and repayment claims resolve against the current holder claimant key, while `controllerXonly` remains the fallback for simpler pilots.
136
141
 
137
142
  Main entrypoints:
138
143
  - `sdk.receivables.define(...)`
@@ -221,3 +226,5 @@ For practical usage you typically need:
221
226
  - a reachable Elements / Liquid RPC endpoint
222
227
 
223
228
  Some commands are SDK-only and work without live spends. Local and testnet e2e flows need the toolchain and, for broadcasted flows, an RPC environment.
229
+
230
+ The dedicated restricted OTC testnet runner clean-skips when RPC credentials are missing so it can stay in public CI and local verification scripts without turning missing env into a hard failure.
package/dist/cli.js CHANGED
@@ -841,6 +841,10 @@ function formatReceivableClaimSummary(input) {
841
841
  `payerEntityId=${input.payerEntityId}`,
842
842
  `payeeEntityId=${input.payeeEntityId}`,
843
843
  `amountSat=${input.amountSat}`,
844
+ input.claimantAuthoritySource ? `claimantAuthoritySource=${input.claimantAuthoritySource}` : undefined,
845
+ input.roleSeparatedAuthorization !== undefined
846
+ ? `roleSeparatedAuthorization=${input.roleSeparatedAuthorization}`
847
+ : undefined,
844
848
  input.bindingMode ? `bindingMode=${input.bindingMode}` : undefined,
845
849
  input.reasonCode ? `reasonCode=${input.reasonCode}` : undefined,
846
850
  input.supportedForm ? `supportedForm=${input.supportedForm}` : undefined,
@@ -3427,6 +3431,7 @@ async function main() {
3427
3431
  nextStateValue: parseJsonArg("next-state-value"),
3428
3432
  stateId: getArg("state-id"),
3429
3433
  holderEntityId: getArg("holder-entity-id"),
3434
+ holderClaimantXonly: getArg("holder-claimant-xonly"),
3430
3435
  fundedAt: getArg("funded-at"),
3431
3436
  });
3432
3437
  printJson({
@@ -3502,6 +3507,8 @@ async function main() {
3502
3507
  payerEntityId: result.claimValue.payerEntityId,
3503
3508
  payeeEntityId: result.claimValue.payeeEntityId,
3504
3509
  amountSat: result.claimValue.amountSat,
3510
+ claimantAuthoritySource: result.report.fundingClaimTrust?.claimantAuthoritySource,
3511
+ roleSeparatedAuthorization: result.report.fundingClaimTrust?.roleSeparatedAuthorization,
3505
3512
  bindingMode: result.report.fundingClaimTrust?.bindingMode,
3506
3513
  reasonCode: result.report.fundingClaimTrust?.reasonCode,
3507
3514
  supportedForm: result.report.fundingClaimTrust?.supportedForm,
@@ -3534,6 +3541,8 @@ async function main() {
3534
3541
  payerEntityId: result.claimValue.payerEntityId,
3535
3542
  payeeEntityId: result.claimValue.payeeEntityId,
3536
3543
  amountSat: result.claimValue.amountSat,
3544
+ claimantAuthoritySource: result.report.fundingClaimTrust?.claimantAuthoritySource,
3545
+ roleSeparatedAuthorization: result.report.fundingClaimTrust?.roleSeparatedAuthorization,
3537
3546
  bindingMode: result.report.fundingClaimTrust?.bindingMode,
3538
3547
  reasonCode: result.report.fundingClaimTrust?.reasonCode,
3539
3548
  supportedForm: result.report.fundingClaimTrust?.supportedForm,
@@ -3575,6 +3584,8 @@ async function main() {
3575
3584
  payerEntityId: result.claimValue.payerEntityId,
3576
3585
  payeeEntityId: result.claimValue.payeeEntityId,
3577
3586
  amountSat: result.claimValue.amountSat,
3587
+ claimantAuthoritySource: result.report.fundingClaimTrust?.claimantAuthoritySource,
3588
+ roleSeparatedAuthorization: result.report.fundingClaimTrust?.roleSeparatedAuthorization,
3578
3589
  bindingMode: result.report.fundingClaimTrust?.bindingMode,
3579
3590
  reasonCode: result.report.fundingClaimTrust?.reasonCode,
3580
3591
  supportedForm: result.report.fundingClaimTrust?.supportedForm,
@@ -3617,6 +3628,8 @@ async function main() {
3617
3628
  payerEntityId: result.claimValue.payerEntityId,
3618
3629
  payeeEntityId: result.claimValue.payeeEntityId,
3619
3630
  amountSat: result.claimValue.amountSat,
3631
+ claimantAuthoritySource: result.report.fundingClaimTrust?.claimantAuthoritySource,
3632
+ roleSeparatedAuthorization: result.report.fundingClaimTrust?.roleSeparatedAuthorization,
3620
3633
  bindingMode: result.report.fundingClaimTrust?.bindingMode,
3621
3634
  reasonCode: result.report.fundingClaimTrust?.reasonCode,
3622
3635
  supportedForm: result.report.fundingClaimTrust?.supportedForm,
@@ -3685,6 +3698,8 @@ async function main() {
3685
3698
  payerEntityId: result.claimValue.payerEntityId,
3686
3699
  payeeEntityId: result.claimValue.payeeEntityId,
3687
3700
  amountSat: result.claimValue.amountSat,
3701
+ claimantAuthoritySource: result.report.repaymentClaimTrust?.claimantAuthoritySource,
3702
+ roleSeparatedAuthorization: result.report.repaymentClaimTrust?.roleSeparatedAuthorization,
3688
3703
  bindingMode: result.report.repaymentClaimTrust?.bindingMode,
3689
3704
  reasonCode: result.report.repaymentClaimTrust?.reasonCode,
3690
3705
  supportedForm: result.report.repaymentClaimTrust?.supportedForm,
@@ -3717,6 +3732,8 @@ async function main() {
3717
3732
  payerEntityId: result.claimValue.payerEntityId,
3718
3733
  payeeEntityId: result.claimValue.payeeEntityId,
3719
3734
  amountSat: result.claimValue.amountSat,
3735
+ claimantAuthoritySource: result.report.repaymentClaimTrust?.claimantAuthoritySource,
3736
+ roleSeparatedAuthorization: result.report.repaymentClaimTrust?.roleSeparatedAuthorization,
3720
3737
  bindingMode: result.report.repaymentClaimTrust?.bindingMode,
3721
3738
  reasonCode: result.report.repaymentClaimTrust?.reasonCode,
3722
3739
  supportedForm: result.report.repaymentClaimTrust?.supportedForm,
@@ -3758,6 +3775,8 @@ async function main() {
3758
3775
  payerEntityId: result.claimValue.payerEntityId,
3759
3776
  payeeEntityId: result.claimValue.payeeEntityId,
3760
3777
  amountSat: result.claimValue.amountSat,
3778
+ claimantAuthoritySource: result.report.repaymentClaimTrust?.claimantAuthoritySource,
3779
+ roleSeparatedAuthorization: result.report.repaymentClaimTrust?.roleSeparatedAuthorization,
3761
3780
  bindingMode: result.report.repaymentClaimTrust?.bindingMode,
3762
3781
  reasonCode: result.report.repaymentClaimTrust?.reasonCode,
3763
3782
  supportedForm: result.report.repaymentClaimTrust?.supportedForm,
@@ -3800,6 +3819,8 @@ async function main() {
3800
3819
  payerEntityId: result.claimValue.payerEntityId,
3801
3820
  payeeEntityId: result.claimValue.payeeEntityId,
3802
3821
  amountSat: result.claimValue.amountSat,
3822
+ claimantAuthoritySource: result.report.repaymentClaimTrust?.claimantAuthoritySource,
3823
+ roleSeparatedAuthorization: result.report.repaymentClaimTrust?.roleSeparatedAuthorization,
3803
3824
  bindingMode: result.report.repaymentClaimTrust?.bindingMode,
3804
3825
  reasonCode: result.report.repaymentClaimTrust?.reasonCode,
3805
3826
  supportedForm: result.report.repaymentClaimTrust?.supportedForm,
@@ -3,6 +3,7 @@ import { ElementsRpcClient } from "../core/rpc";
3
3
  import { BondEvidenceBundle, OutputBindingSupportEvaluation, OutputBindingSupportMatrix, PolicyEvidenceBundle, ReceivableEvidenceBundle, PolicyTemplateManifestValidationResult, DefinitionInput, DefinitionVerificationResult, CompileFromFileInput, CompileFromPresetInput, DefinitionDescriptor, StateDocumentDescriptor, StateDocumentInput, StateVerificationResult, SimplicityArtifact, SimplicityClientConfig } from "../core/types";
4
4
  import { RelayerClient } from "../gasless/RelayerClient";
5
5
  import { GaslessTransferInput, GaslessTransferResult, RelayerClientConfig } from "../gasless/types";
6
+ import * as liquidX402 from "../x402";
6
7
  import { CompiledContract } from "./ContractFactory";
7
8
  import { DeployedContract } from "./DeployedContract";
8
9
  import { prepareRedemption, prepareClosing, exportFinalityPayload, buildSettlement, verifySettlement, define, executeClosing, executeRedemption, exportEvidence, inspectClosing, inspectRedemption, issue, load, verify, verifyIssuanceHistory, verifyClosing, verifyRedemption } from "../domain/bond";
@@ -14,6 +15,16 @@ export declare class SimplicityClient {
14
15
  readonly rpc: ElementsRpcClient;
15
16
  readonly payments: {
16
17
  gaslessTransfer: (input: GaslessTransferInput) => Promise<GaslessTransferResult>;
18
+ x402: {
19
+ assets: typeof liquidX402.listLiquidX402Assets;
20
+ resolveAsset: typeof liquidX402.resolveLiquidX402Asset;
21
+ buildRequirements: typeof liquidX402.buildLiquidX402Requirements;
22
+ encodePayment: typeof liquidX402.encodeLiquidXPayment;
23
+ decodePayment: typeof liquidX402.decodeLiquidXPayment;
24
+ preparePsetPayment: (input: liquidX402.LiquidX402PreparePsetPaymentInput) => Promise<liquidX402.LiquidX402PreparePsetPaymentResult>;
25
+ verify: (input: liquidX402.LiquidX402VerifyPaymentInput) => Promise<liquidX402.LiquidX402VerifyPaymentResult>;
26
+ settle: (input: liquidX402.LiquidX402SettlePaymentInput) => Promise<liquidX402.LiquidX402SettlePaymentResult>;
27
+ };
17
28
  };
18
29
  readonly outputBinding: {
19
30
  describeSupport: () => OutputBindingSupportMatrix;
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.SimplicityClient = void 0;
4
37
  exports.createSimplicityClient = createSimplicityClient;
@@ -10,6 +43,7 @@ const errors_1 = require("../core/errors");
10
43
  const outputBinding_1 = require("../core/outputBinding");
11
44
  const rpc_1 = require("../core/rpc");
12
45
  const RelayerClient_1 = require("../gasless/RelayerClient");
46
+ const liquidX402 = __importStar(require("../x402"));
13
47
  const ContractFactory_1 = require("./ContractFactory");
14
48
  const DeployedContract_1 = require("./DeployedContract");
15
49
  const bond_1 = require("../domain/bond");
@@ -30,6 +64,16 @@ class SimplicityClient {
30
64
  this.rpc = new rpc_1.ElementsRpcClient(config.rpc);
31
65
  this.payments = {
32
66
  gaslessTransfer: async (input) => this.gaslessTransfer(input),
67
+ x402: {
68
+ assets: liquidX402.listLiquidX402Assets,
69
+ resolveAsset: liquidX402.resolveLiquidX402Asset,
70
+ buildRequirements: liquidX402.buildLiquidX402Requirements,
71
+ encodePayment: liquidX402.encodeLiquidXPayment,
72
+ decodePayment: liquidX402.decodeLiquidXPayment,
73
+ preparePsetPayment: async (input) => liquidX402.prepareLiquidX402PsetPayment(this.rpc, input),
74
+ verify: async (input) => liquidX402.verifyLiquidX402Payment(this.rpc, input),
75
+ settle: async (input) => liquidX402.settleLiquidX402Payment(this.rpc, input),
76
+ },
33
77
  };
34
78
  this.outputBinding = {
35
79
  describeSupport: () => (0, outputBinding_1.describeOutputBindingSupport)(),
@@ -548,6 +548,7 @@ export type ReceivableStatus = "ORIGINATED" | "FUNDED" | "PARTIALLY_REPAID" | "R
548
548
  export type ReceivableTransitionType = "ORIGINATE" | "FUND" | "REPAY" | "WRITE_OFF";
549
549
  export type ReceivableClosingReason = "REPAID" | "DEFAULTED" | "CANCELLED";
550
550
  export type ReceivableClaimKind = "FUNDING" | "REPAYMENT";
551
+ export type ReceivableClaimAuthoritySource = "originator-claimant" | "holder-claimant" | "controller-fallback";
551
552
  export type ReceivableVerificationReportSchemaVersion = "receivable-verification-report/v1";
552
553
  export type ReceivableEvidenceBundleSchemaVersion = "receivable-evidence-bundle/v1";
553
554
  export type ReceivableFinalityPayloadSchemaVersion = "receivable-finality-payload/v1";
@@ -559,6 +560,7 @@ export interface ReceivableDefinition {
559
560
  faceValue: number;
560
561
  dueDate: string;
561
562
  controllerXonly: string;
563
+ originatorClaimantXonly?: string;
562
564
  }
563
565
  export interface ReceivableStateTransition {
564
566
  type: ReceivableTransitionType;
@@ -573,6 +575,7 @@ export interface ReceivableState {
573
575
  holderEntityId: string;
574
576
  currencyAssetId: string;
575
577
  controllerXonly: string;
578
+ holderClaimantXonly?: string;
576
579
  faceValue: number;
577
580
  outstandingAmount: number;
578
581
  repaidAmount: number;
@@ -627,6 +630,8 @@ export interface ReceivableClosingTrust {
627
630
  }
628
631
  export interface ReceivableClaimTrust {
629
632
  claimKind: ReceivableClaimKind;
633
+ claimantAuthoritySource: ReceivableClaimAuthoritySource;
634
+ roleSeparatedAuthorization: boolean;
630
635
  generated: boolean;
631
636
  stateStatusEligible: boolean;
632
637
  receivableIdMatch: boolean;
@@ -5,5 +5,6 @@
5
5
  "currencyAssetId": "bitcoin",
6
6
  "faceValue": 10000,
7
7
  "dueDate": "2027-12-31T00:00:00Z",
8
- "controllerXonly": "1111111111111111111111111111111111111111111111111111111111111111"
8
+ "controllerXonly": "3333333333333333333333333333333333333333333333333333333333333333",
9
+ "originatorClaimantXonly": "1111111111111111111111111111111111111111111111111111111111111111"
9
10
  }
@@ -2,7 +2,7 @@
2
2
  "claimId": "REC-001-FUNDING-CLAIM",
3
3
  "claimKind": "FUNDING",
4
4
  "receivableId": "REC-001",
5
- "currentStateHash": "7a61cc669844f3fd96165c99e3ca42cfae916e824dec4d60e51d56ef574e041a",
5
+ "currentStateHash": "13147d187ce3200d7044d73d7b86b93140c43f29dd048f919569f5eb7b47c562",
6
6
  "currentStatus": "FUNDED",
7
7
  "payerEntityId": "fund-1",
8
8
  "payeeEntityId": "originator-1",
@@ -0,0 +1,13 @@
1
+ {
2
+ "claimId": "REC-001-REPAYMENT-CLAIM-PARTIAL",
3
+ "claimKind": "REPAYMENT",
4
+ "receivableId": "REC-001",
5
+ "currentStateHash": "34e4db6639ad5b3ccb555320af22fb0eca2ab393ff198602ce5ca69d398cec31",
6
+ "currentStatus": "PARTIALLY_REPAID",
7
+ "payerEntityId": "debtor-1",
8
+ "payeeEntityId": "fund-1",
9
+ "claimantXonly": "2222222222222222222222222222222222222222222222222222222222222222",
10
+ "currencyAssetId": "bitcoin",
11
+ "amountSat": 4000,
12
+ "eventTimestamp": "2027-02-01T00:00:00Z"
13
+ }
@@ -1,13 +1,13 @@
1
1
  {
2
- "claimId": "REC-001-REPAYMENT-CLAIM",
2
+ "claimId": "REC-001-REPAYMENT-CLAIM-FINAL",
3
3
  "claimKind": "REPAYMENT",
4
4
  "receivableId": "REC-001",
5
- "currentStateHash": "13ae81254644a47f33492812584e169b4ae2051dfedc5ad46d00510c137dc333",
5
+ "currentStateHash": "a18fdc99bf37de415bfa242a387cdb41b943d2581bfe177aec51c3e42e9e40bf",
6
6
  "currentStatus": "REPAID",
7
7
  "payerEntityId": "debtor-1",
8
8
  "payeeEntityId": "fund-1",
9
- "claimantXonly": "1111111111111111111111111111111111111111111111111111111111111111",
9
+ "claimantXonly": "2222222222222222222222222222222222222222222222222222222222222222",
10
10
  "currencyAssetId": "bitcoin",
11
- "amountSat": 10000,
12
- "eventTimestamp": "2027-02-01T00:00:00Z"
11
+ "amountSat": 6000,
12
+ "eventTimestamp": "2027-03-01T00:00:00Z"
13
13
  }
@@ -5,13 +5,14 @@
5
5
  "debtorEntityId": "debtor-1",
6
6
  "holderEntityId": "fund-1",
7
7
  "currencyAssetId": "bitcoin",
8
- "controllerXonly": "1111111111111111111111111111111111111111111111111111111111111111",
8
+ "controllerXonly": "3333333333333333333333333333333333333333333333333333333333333333",
9
+ "holderClaimantXonly": "2222222222222222222222222222222222222222222222222222222222222222",
9
10
  "faceValue": 10000,
10
11
  "outstandingAmount": 10000,
11
12
  "repaidAmount": 0,
12
13
  "status": "FUNDED",
13
14
  "createdAt": "2027-01-02T00:00:00Z",
14
- "previousStateHash": "575a96c8f73f9a68d8bc76f5683cf042f89dcff73c7136939daf26be6128d935",
15
+ "previousStateHash": "cdd1a8e867611a0bf486c35a7811c80c2459f28ca988c22f789fbacdd4ee5c9e",
15
16
  "lastTransition": {
16
17
  "type": "FUND",
17
18
  "amount": 10000,
@@ -5,7 +5,8 @@
5
5
  "debtorEntityId": "debtor-1",
6
6
  "holderEntityId": "originator-1",
7
7
  "currencyAssetId": "bitcoin",
8
- "controllerXonly": "1111111111111111111111111111111111111111111111111111111111111111",
8
+ "controllerXonly": "3333333333333333333333333333333333333333333333333333333333333333",
9
+ "holderClaimantXonly": "1111111111111111111111111111111111111111111111111111111111111111",
9
10
  "faceValue": 10000,
10
11
  "outstandingAmount": 10000,
11
12
  "repaidAmount": 0,
@@ -0,0 +1,21 @@
1
+ {
2
+ "stateId": "REC-001-S2",
3
+ "receivableId": "REC-001",
4
+ "originatorEntityId": "originator-1",
5
+ "debtorEntityId": "debtor-1",
6
+ "holderEntityId": "fund-1",
7
+ "currencyAssetId": "bitcoin",
8
+ "controllerXonly": "3333333333333333333333333333333333333333333333333333333333333333",
9
+ "holderClaimantXonly": "2222222222222222222222222222222222222222222222222222222222222222",
10
+ "faceValue": 10000,
11
+ "outstandingAmount": 6000,
12
+ "repaidAmount": 4000,
13
+ "status": "PARTIALLY_REPAID",
14
+ "createdAt": "2027-02-01T00:00:00Z",
15
+ "previousStateHash": "13147d187ce3200d7044d73d7b86b93140c43f29dd048f919569f5eb7b47c562",
16
+ "lastTransition": {
17
+ "type": "REPAY",
18
+ "amount": 4000,
19
+ "at": "2027-02-01T00:00:00Z"
20
+ }
21
+ }
@@ -1,20 +1,21 @@
1
1
  {
2
- "stateId": "REC-001-S2",
2
+ "stateId": "REC-001-S3",
3
3
  "receivableId": "REC-001",
4
4
  "originatorEntityId": "originator-1",
5
5
  "debtorEntityId": "debtor-1",
6
6
  "holderEntityId": "fund-1",
7
7
  "currencyAssetId": "bitcoin",
8
- "controllerXonly": "1111111111111111111111111111111111111111111111111111111111111111",
8
+ "controllerXonly": "3333333333333333333333333333333333333333333333333333333333333333",
9
+ "holderClaimantXonly": "2222222222222222222222222222222222222222222222222222222222222222",
9
10
  "faceValue": 10000,
10
11
  "outstandingAmount": 0,
11
12
  "repaidAmount": 10000,
12
13
  "status": "REPAID",
13
- "createdAt": "2027-02-01T00:00:00Z",
14
- "previousStateHash": "7a61cc669844f3fd96165c99e3ca42cfae916e824dec4d60e51d56ef574e041a",
14
+ "createdAt": "2027-03-01T00:00:00Z",
15
+ "previousStateHash": "34e4db6639ad5b3ccb555320af22fb0eca2ab393ff198602ce5ca69d398cec31",
15
16
  "lastTransition": {
16
17
  "type": "REPAY",
17
- "amount": 10000,
18
- "at": "2027-02-01T00:00:00Z"
18
+ "amount": 6000,
19
+ "at": "2027-03-01T00:00:00Z"
19
20
  }
20
21
  }
@@ -142,6 +142,7 @@ export declare function prepareFunding(sdk: SimplicityClient, input: {
142
142
  nextStateValue?: ReceivableState;
143
143
  stateId?: string;
144
144
  holderEntityId?: string;
145
+ holderClaimantXonly?: string;
145
146
  fundedAt?: string;
146
147
  }): Promise<{
147
148
  verified: boolean;
@@ -515,6 +515,7 @@ async function prepareFunding(sdk, input) {
515
515
  previous: previous.value,
516
516
  stateId: input.stateId ?? `${previous.value.receivableId}-FUNDED`,
517
517
  holderEntityId: input.holderEntityId ?? previous.value.holderEntityId,
518
+ holderClaimantXonly: input.holderClaimantXonly,
518
519
  fundedAt: input.fundedAt ?? new Date().toISOString(),
519
520
  }),
520
521
  });
@@ -545,6 +546,7 @@ async function loadReceivableFundingClaimDocument(sdk, input) {
545
546
  }
546
547
  const value = (0, receivableValidation_1.buildReceivableFundingClaimDescriptor)({
547
548
  claimId: input.claimId,
549
+ definition: input.definitionValue,
548
550
  currentState: input.currentStateValue,
549
551
  payerEntityId: input.payerEntityId,
550
552
  payeeEntityId: input.payeeEntityId,
@@ -728,6 +730,7 @@ async function prepareFundingClaim(sdk, input) {
728
730
  const claim = await loadReceivableFundingClaimDocument(sdk, {
729
731
  fundingClaimPath: input.fundingClaimPath,
730
732
  fundingClaimValue: input.fundingClaimValue,
733
+ definitionValue: definition.value,
731
734
  currentStateValue: currentState.value,
732
735
  claimId: input.claimId ?? `${currentState.value.receivableId}-FUNDING-CLAIM`,
733
736
  payerEntityId: input.payerEntityId,
@@ -741,6 +744,7 @@ async function prepareFundingClaim(sdk, input) {
741
744
  ? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
742
745
  : undefined;
743
746
  const claimChecks = (0, receivableValidation_1.validateReceivableFundingClaimAgainstState)({
747
+ definition: definition.value,
744
748
  currentState: currentState.value,
745
749
  claim: claim.value,
746
750
  });
@@ -784,12 +788,14 @@ async function verifyFundingClaim(sdk, input) {
784
788
  const claim = await loadReceivableFundingClaimDocument(sdk, {
785
789
  fundingClaimPath: input.fundingClaimPath,
786
790
  fundingClaimValue: input.fundingClaimValue,
791
+ definitionValue: definition.value,
787
792
  });
788
793
  const crossChecks = (0, receivableValidation_1.validateReceivableCrossChecks)(definition.value, currentState.value);
789
794
  const lineageChecks = history.length > 0
790
795
  ? (0, receivableValidation_1.verifyReceivableStateHistory)({ history: history.map((entry) => entry.value) })
791
796
  : undefined;
792
797
  const claimChecks = (0, receivableValidation_1.validateReceivableFundingClaimAgainstState)({
798
+ definition: definition.value,
793
799
  currentState: currentState.value,
794
800
  claim: claim.value,
795
801
  });
@@ -887,6 +893,8 @@ async function inspectFundingClaim(sdk, input) {
887
893
  claimantXonlyCommitted: verified.report.fundingClaimTrust?.claimantXonlyCommitted ?? true,
888
894
  checks: {
889
895
  claimKind: verified.report.fundingClaimTrust?.claimKind ?? "FUNDING",
896
+ claimantAuthoritySource: verified.report.fundingClaimTrust?.claimantAuthoritySource ?? "controller-fallback",
897
+ roleSeparatedAuthorization: verified.report.fundingClaimTrust?.roleSeparatedAuthorization ?? false,
890
898
  stateStatusEligible: verified.report.fundingClaimTrust?.stateStatusEligible ?? false,
891
899
  receivableIdMatch: verified.report.fundingClaimTrust?.receivableIdMatch ?? false,
892
900
  currentStateHashMatch: verified.report.fundingClaimTrust?.currentStateHashMatch ?? false,
@@ -1101,6 +1109,8 @@ async function inspectRepaymentClaim(sdk, input) {
1101
1109
  claimantXonlyCommitted: verified.report.repaymentClaimTrust?.claimantXonlyCommitted ?? true,
1102
1110
  checks: {
1103
1111
  claimKind: verified.report.repaymentClaimTrust?.claimKind ?? "REPAYMENT",
1112
+ claimantAuthoritySource: verified.report.repaymentClaimTrust?.claimantAuthoritySource ?? "controller-fallback",
1113
+ roleSeparatedAuthorization: verified.report.repaymentClaimTrust?.roleSeparatedAuthorization ?? false,
1104
1114
  stateStatusEligible: verified.report.repaymentClaimTrust?.stateStatusEligible ?? false,
1105
1115
  receivableIdMatch: verified.report.repaymentClaimTrust?.receivableIdMatch ?? false,
1106
1116
  currentStateHashMatch: verified.report.repaymentClaimTrust?.currentStateHashMatch ?? false,
@@ -37,6 +37,7 @@ export declare function buildFundedReceivableState(input: {
37
37
  previous: ReceivableState;
38
38
  stateId: string;
39
39
  holderEntityId: string;
40
+ holderClaimantXonly?: string;
40
41
  fundedAt: string;
41
42
  }): ReceivableState;
42
43
  export declare function applyReceivableRepayment(input: {
@@ -59,6 +60,7 @@ export declare function buildReceivableClosingDescriptor(input: {
59
60
  }): ReceivableClosingDescriptor;
60
61
  export declare function buildReceivableFundingClaimDescriptor(input: {
61
62
  claimId: string;
63
+ definition?: ReceivableDefinition;
62
64
  currentState: ReceivableState;
63
65
  payerEntityId?: string;
64
66
  payeeEntityId?: string;
@@ -76,6 +78,7 @@ export declare function buildReceivableRepaymentClaimDescriptor(input: {
76
78
  eventTimestamp?: string;
77
79
  }): ReceivableRepaymentClaimDescriptor;
78
80
  export declare function validateReceivableFundingClaimAgainstState(input: {
81
+ definition: ReceivableDefinition;
79
82
  currentState: ReceivableState;
80
83
  claim: ReceivableFundingClaimDescriptor;
81
84
  }): Omit<ReceivableClaimTrust, "generated" | "bindingMode" | "requestedMode" | "supportedForm" | "reasonCode" | "nextReceiverRuntimeCommitted" | "nextOutputHashRuntimeBound" | "nextOutputScriptRuntimeBound" | "amountRuntimeBound" | "autoDerived" | "fallbackReason" | "bindingInputs" | "claimantXonlyCommitted">;
@@ -119,6 +119,9 @@ function validateReceivableDefinition(value) {
119
119
  assertFinitePositiveNumber(definition?.faceValue, "RECEIVABLE_FACE_VALUE_INVALID", "faceValue must be a positive finite number");
120
120
  assertIsoDateLike(definition?.dueDate, "RECEIVABLE_DUE_DATE_INVALID", "dueDate must be an ISO8601 string");
121
121
  assertXonlyPubkey(definition?.controllerXonly, "RECEIVABLE_CONTROLLER_INVALID", "controllerXonly must be a 32-byte xonly public key");
122
+ if (definition.originatorClaimantXonly !== undefined) {
123
+ assertXonlyPubkey(definition.originatorClaimantXonly, "RECEIVABLE_ORIGINATOR_CLAIMANT_INVALID", "originatorClaimantXonly must be a 32-byte xonly public key");
124
+ }
122
125
  return {
123
126
  receivableId: definition.receivableId,
124
127
  originatorEntityId: definition.originatorEntityId,
@@ -127,6 +130,7 @@ function validateReceivableDefinition(value) {
127
130
  faceValue: definition.faceValue,
128
131
  dueDate: definition.dueDate,
129
132
  controllerXonly: definition.controllerXonly,
133
+ ...(definition.originatorClaimantXonly ? { originatorClaimantXonly: definition.originatorClaimantXonly } : {}),
130
134
  };
131
135
  }
132
136
  function validateReceivableState(value) {
@@ -138,6 +142,9 @@ function validateReceivableState(value) {
138
142
  assertNonEmptyString(state?.holderEntityId, "RECEIVABLE_HOLDER_INVALID", "holderEntityId must be a non-empty string");
139
143
  assertNonEmptyString(state?.currencyAssetId, "RECEIVABLE_CURRENCY_INVALID", "currencyAssetId must be a non-empty string");
140
144
  assertXonlyPubkey(state?.controllerXonly, "RECEIVABLE_CONTROLLER_INVALID", "controllerXonly must be a 32-byte xonly public key");
145
+ if (state.holderClaimantXonly !== undefined) {
146
+ assertXonlyPubkey(state.holderClaimantXonly, "RECEIVABLE_HOLDER_CLAIMANT_INVALID", "holderClaimantXonly must be a 32-byte xonly public key");
147
+ }
141
148
  assertFinitePositiveNumber(state?.faceValue, "RECEIVABLE_FACE_VALUE_INVALID", "faceValue must be a positive finite number");
142
149
  assertFiniteNonNegativeNumber(state?.outstandingAmount, "RECEIVABLE_OUTSTANDING_INVALID", "outstandingAmount must be a non-negative finite number");
143
150
  assertFiniteNonNegativeNumber(state?.repaidAmount, "RECEIVABLE_REPAID_INVALID", "repaidAmount must be a non-negative finite number");
@@ -240,6 +247,7 @@ function validateReceivableState(value) {
240
247
  holderEntityId: state.holderEntityId,
241
248
  currencyAssetId: state.currencyAssetId,
242
249
  controllerXonly: state.controllerXonly,
250
+ ...(state.holderClaimantXonly ? { holderClaimantXonly: state.holderClaimantXonly } : {}),
243
251
  faceValue: state.faceValue,
244
252
  outstandingAmount: state.outstandingAmount,
245
253
  repaidAmount: state.repaidAmount,
@@ -432,6 +440,9 @@ function buildFundedReceivableState(input) {
432
440
  ...previous,
433
441
  stateId: input.stateId,
434
442
  holderEntityId: input.holderEntityId,
443
+ holderClaimantXonly: input.holderEntityId === previous.holderEntityId
444
+ ? previous.holderClaimantXonly ?? previous.controllerXonly
445
+ : input.holderClaimantXonly ?? previous.controllerXonly,
435
446
  status: "FUNDED",
436
447
  createdAt: input.fundedAt,
437
448
  previousStateHash: summarizeReceivableState(previous).hash,
@@ -508,6 +519,7 @@ function buildReceivableClosingDescriptor(input) {
508
519
  });
509
520
  }
510
521
  function buildReceivableFundingClaimDescriptor(input) {
522
+ const definition = input.definition ? validateReceivableDefinition(input.definition) : undefined;
511
523
  const currentState = validateReceivableState(input.currentState);
512
524
  const currentStateHash = summarizeReceivableState(currentState).hash;
513
525
  return validateReceivableFundingClaimDescriptor({
@@ -518,7 +530,7 @@ function buildReceivableFundingClaimDescriptor(input) {
518
530
  currentStatus: currentState.status,
519
531
  payerEntityId: input.payerEntityId ?? currentState.holderEntityId,
520
532
  payeeEntityId: input.payeeEntityId ?? currentState.originatorEntityId,
521
- claimantXonly: input.claimantXonly ?? currentState.controllerXonly,
533
+ claimantXonly: input.claimantXonly ?? definition?.originatorClaimantXonly ?? currentState.controllerXonly,
522
534
  currencyAssetId: currentState.currencyAssetId,
523
535
  amountSat: input.amountSat ?? currentState.lastTransition?.amount ?? currentState.outstandingAmount,
524
536
  eventTimestamp: input.eventTimestamp ?? currentState.lastTransition?.at ?? currentState.createdAt,
@@ -535,15 +547,41 @@ function buildReceivableRepaymentClaimDescriptor(input) {
535
547
  currentStatus: currentState.status,
536
548
  payerEntityId: input.payerEntityId ?? currentState.debtorEntityId,
537
549
  payeeEntityId: input.payeeEntityId ?? currentState.holderEntityId,
538
- claimantXonly: input.claimantXonly ?? currentState.controllerXonly,
550
+ claimantXonly: input.claimantXonly ?? currentState.holderClaimantXonly ?? currentState.controllerXonly,
539
551
  currencyAssetId: currentState.currencyAssetId,
540
552
  amountSat: input.amountSat ?? currentState.lastTransition?.amount ?? currentState.repaidAmount,
541
553
  eventTimestamp: input.eventTimestamp ?? currentState.lastTransition?.at ?? currentState.createdAt,
542
554
  });
543
555
  }
556
+ function resolveFundingClaimAuthority(definition, currentState) {
557
+ if (definition.originatorClaimantXonly) {
558
+ return {
559
+ claimantXonly: definition.originatorClaimantXonly,
560
+ authoritySource: "originator-claimant",
561
+ };
562
+ }
563
+ return {
564
+ claimantXonly: currentState.controllerXonly,
565
+ authoritySource: "controller-fallback",
566
+ };
567
+ }
568
+ function resolveRepaymentClaimAuthority(currentState) {
569
+ if (currentState.holderClaimantXonly) {
570
+ return {
571
+ claimantXonly: currentState.holderClaimantXonly,
572
+ authoritySource: "holder-claimant",
573
+ };
574
+ }
575
+ return {
576
+ claimantXonly: currentState.controllerXonly,
577
+ authoritySource: "controller-fallback",
578
+ };
579
+ }
544
580
  function validateReceivableFundingClaimAgainstState(input) {
581
+ const definition = validateReceivableDefinition(input.definition);
545
582
  const currentState = validateReceivableState(input.currentState);
546
583
  const claim = validateReceivableFundingClaimDescriptor(input.claim);
584
+ const authority = resolveFundingClaimAuthority(definition, currentState);
547
585
  const currentStateHash = summarizeReceivableState(currentState).hash;
548
586
  const stateStatusEligible = currentState.status === "FUNDED";
549
587
  const receivableIdMatch = claim.receivableId === currentState.receivableId;
@@ -551,12 +589,14 @@ function validateReceivableFundingClaimAgainstState(input) {
551
589
  const currentStatusMatch = claim.currentStatus === currentState.status;
552
590
  const payerEntityMatch = claim.payerEntityId === currentState.holderEntityId;
553
591
  const payeeEntityMatch = claim.payeeEntityId === currentState.originatorEntityId;
554
- const claimantXonlyMatch = claim.claimantXonly === currentState.controllerXonly;
592
+ const claimantXonlyMatch = claim.claimantXonly === authority.claimantXonly;
555
593
  const currencyAssetMatch = claim.currencyAssetId === currentState.currencyAssetId;
556
594
  const amountMatch = currentState.lastTransition?.type === "FUND" && claim.amountSat === currentState.lastTransition.amount;
557
595
  const eventTimestampMatch = currentState.lastTransition?.type === "FUND" && claim.eventTimestamp === currentState.lastTransition.at;
558
596
  return {
559
597
  claimKind: "FUNDING",
598
+ claimantAuthoritySource: authority.authoritySource,
599
+ roleSeparatedAuthorization: authority.authoritySource !== "controller-fallback",
560
600
  stateStatusEligible,
561
601
  receivableIdMatch,
562
602
  currentStateHashMatch,
@@ -582,6 +622,7 @@ function validateReceivableFundingClaimAgainstState(input) {
582
622
  function validateReceivableRepaymentClaimAgainstState(input) {
583
623
  const currentState = validateReceivableState(input.currentState);
584
624
  const claim = validateReceivableRepaymentClaimDescriptor(input.claim);
625
+ const authority = resolveRepaymentClaimAuthority(currentState);
585
626
  const currentStateHash = summarizeReceivableState(currentState).hash;
586
627
  const stateStatusEligible = currentState.status === "PARTIALLY_REPAID" || currentState.status === "REPAID";
587
628
  const receivableIdMatch = claim.receivableId === currentState.receivableId;
@@ -589,12 +630,14 @@ function validateReceivableRepaymentClaimAgainstState(input) {
589
630
  const currentStatusMatch = claim.currentStatus === currentState.status;
590
631
  const payerEntityMatch = claim.payerEntityId === currentState.debtorEntityId;
591
632
  const payeeEntityMatch = claim.payeeEntityId === currentState.holderEntityId;
592
- const claimantXonlyMatch = claim.claimantXonly === currentState.controllerXonly;
633
+ const claimantXonlyMatch = claim.claimantXonly === authority.claimantXonly;
593
634
  const currencyAssetMatch = claim.currencyAssetId === currentState.currencyAssetId;
594
635
  const amountMatch = currentState.lastTransition?.type === "REPAY" && claim.amountSat === currentState.lastTransition.amount;
595
636
  const eventTimestampMatch = currentState.lastTransition?.type === "REPAY" && claim.eventTimestamp === currentState.lastTransition.at;
596
637
  return {
597
638
  claimKind: "REPAYMENT",
639
+ claimantAuthoritySource: authority.authoritySource,
640
+ roleSeparatedAuthorization: authority.authoritySource !== "controller-fallback",
598
641
  stateStatusEligible,
599
642
  receivableIdMatch,
600
643
  currentStateHashMatch,
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export { createSimplicityClient, SimplicityClient } from "./client/SimplicityCli
2
2
  export { CompiledContract } from "./client/ContractFactory";
3
3
  export { DeployedContract } from "./client/DeployedContract";
4
4
  export { RelayerClient } from "./gasless/RelayerClient";
5
+ export { ElementsRpcClient } from "./core/rpc";
6
+ export * from "./x402";
5
7
  export * from "./core/types";
6
8
  export * from "./core/errors";
7
9
  export { listPresets, getPresetOrThrow } from "./core/presets";
package/dist/index.js CHANGED
@@ -14,10 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.verifyPositionReceipt = exports.signPositionReceipt = exports.verifyCapitalCall = exports.executeCapitalCallRefund = exports.inspectCapitalCallRefund = exports.executeCapitalCallRollover = exports.inspectCapitalCallRollover = exports.executeCapitalCallClaim = exports.inspectCapitalCallClaim = exports.prepareCapitalCall = exports.loadFund = exports.verifyFund = exports.defineFund = exports.exportFinalityPayload = exports.exportBondEvidence = exports.verifyClosing = exports.executeClosing = exports.inspectClosing = exports.prepareClosing = exports.verifySettlement = exports.buildSettlement = exports.verifyRedemption = exports.executeRedemption = exports.inspectRedemption = exports.prepareRedemption = exports.issueBond = exports.loadBond = exports.verifyIssuanceHistory = exports.verifyBond = exports.defineBond = exports.verifyStateDescriptorAgainstArtifact = exports.verifyStateAgainstArtifact = exports.buildArtifactStateMetadata = exports.loadStateInput = exports.verifyDefinitionDescriptorAgainstArtifact = exports.verifyDefinitionAgainstArtifact = exports.buildArtifactDefinitionMetadata = exports.loadDefinitionInput = exports.evaluateOutputBindingSupport = exports.describeOutputBindingSupport = exports.normalizeArtifact = exports.saveArtifact = exports.loadArtifact = exports.getPresetOrThrow = exports.listPresets = exports.RelayerClient = exports.DeployedContract = exports.CompiledContract = exports.SimplicityClient = exports.createSimplicityClient = void 0;
18
- exports.validateCapitalCallState = exports.validateFundDefinition = exports.summarizeFundFinalityPayload = exports.summarizeFundClosingDescriptor = exports.summarizeDistributionDescriptor = exports.summarizeLPPositionReceipt = exports.summarizeCapitalCallState = exports.summarizeFundDefinition = exports.validateBondSettlementMatchesExpected = exports.validateBondSettlementDescriptor = exports.summarizeBondSettlementDescriptor = exports.verifyBondIssuanceHistory = exports.summarizeBondIssuanceState = exports.buildRedeemedBondIssuanceState = exports.validateBondStateTransition = exports.validateBondCrossChecks = exports.validateBondIssuanceState = exports.validateBondDefinition = exports.exportReceivableFinalityPayload = exports.exportReceivableEvidence = exports.verifyReceivableStateHistory = exports.verifyReceivableClosing = exports.prepareReceivableClosing = exports.verifyReceivableWriteOff = exports.prepareReceivableWriteOff = exports.verifyReceivableRepaymentClaim = exports.executeReceivableRepaymentClaim = exports.inspectReceivableRepaymentClaim = exports.prepareReceivableRepaymentClaim = exports.verifyReceivableRepayment = exports.prepareReceivableRepayment = exports.verifyReceivableFundingClaim = exports.executeReceivableFundingClaim = exports.inspectReceivableFundingClaim = exports.prepareReceivableFundingClaim = exports.verifyReceivableFunding = exports.prepareReceivableFunding = exports.loadReceivable = exports.verifyReceivable = exports.defineReceivable = exports.exportFundFinalityPayload = exports.exportFundEvidence = exports.verifyFundClosing = exports.prepareFundClosing = exports.verifyDistribution = exports.executeDistributionClaim = exports.inspectDistributionClaim = exports.reconcilePosition = exports.prepareDistribution = exports.verifyPositionReceiptChain = void 0;
19
- exports.verifyTransfer = exports.verifyState = exports.inspectTransfer = exports.executeTransfer = exports.prepareTransfer = exports.issue = exports.validatePolicyTemplateParams = exports.describePolicyTemplate = exports.validatePolicyTemplateManifest = exports.loadPolicyTemplateManifest = exports.listPolicyTemplates = exports.buildPolicyOutputDescriptor = exports.compilePolicyStateContract = exports.verifyReceivableStateHistoryValidation = exports.validateReceivableWriteOffTransition = exports.validateReceivableRepaymentTransition = exports.validateReceivableFundingTransition = exports.validateReceivableCrossChecks = exports.validateReceivableState = exports.validateReceivableRepaymentClaimDescriptor = exports.validateReceivableRepaymentClaimAgainstState = exports.validateReceivableFundingClaimDescriptor = exports.validateReceivableFundingClaimAgainstState = exports.validateReceivableDefinition = exports.validateReceivableClosingDescriptor = exports.validateReceivableClosingAgainstState = exports.summarizeReceivableState = exports.summarizeReceivableRepaymentClaimDescriptor = exports.summarizeReceivableFundingClaimDescriptor = exports.summarizeReceivableDefinition = exports.summarizeReceivableClosingDescriptor = exports.buildReceivableRepaymentClaimDescriptor = exports.buildReceivableFundingClaimDescriptor = exports.buildReceivableClosingDescriptor = exports.buildFundedReceivableState = exports.buildDefaultedReceivableState = exports.applyReceivableRepayment = exports.buildFundClosingDescriptor = exports.buildDistributionDescriptor = exports.applyDistributionsToReceipt = exports.applyDistributionToReceipt = exports.buildLPPositionReceipt = exports.buildRefundedCapitalCallState = exports.buildClaimedCapitalCallState = exports.validateClosingAgainstReceipt = exports.validateDistributionAgainstReceipt = exports.validateFundCrossChecks = exports.validateFundClosingDescriptor = exports.validateDistributionDescriptor = exports.validateLPPositionReceipt = void 0;
20
- exports.validatePolicyTransferDescriptor = exports.validatePolicyOutputDescriptor = exports.validatePolicyState = exports.summarizePolicyTransferDescriptor = exports.summarizePolicyOutputDescriptor = exports.summarizePolicyState = exports.exportPolicyEvidence = void 0;
17
+ exports.signPositionReceipt = exports.verifyCapitalCall = exports.executeCapitalCallRefund = exports.inspectCapitalCallRefund = exports.executeCapitalCallRollover = exports.inspectCapitalCallRollover = exports.executeCapitalCallClaim = exports.inspectCapitalCallClaim = exports.prepareCapitalCall = exports.loadFund = exports.verifyFund = exports.defineFund = exports.exportFinalityPayload = exports.exportBondEvidence = exports.verifyClosing = exports.executeClosing = exports.inspectClosing = exports.prepareClosing = exports.verifySettlement = exports.buildSettlement = exports.verifyRedemption = exports.executeRedemption = exports.inspectRedemption = exports.prepareRedemption = exports.issueBond = exports.loadBond = exports.verifyIssuanceHistory = exports.verifyBond = exports.defineBond = exports.verifyStateDescriptorAgainstArtifact = exports.verifyStateAgainstArtifact = exports.buildArtifactStateMetadata = exports.loadStateInput = exports.verifyDefinitionDescriptorAgainstArtifact = exports.verifyDefinitionAgainstArtifact = exports.buildArtifactDefinitionMetadata = exports.loadDefinitionInput = exports.evaluateOutputBindingSupport = exports.describeOutputBindingSupport = exports.normalizeArtifact = exports.saveArtifact = exports.loadArtifact = exports.getPresetOrThrow = exports.listPresets = exports.ElementsRpcClient = exports.RelayerClient = exports.DeployedContract = exports.CompiledContract = exports.SimplicityClient = exports.createSimplicityClient = void 0;
18
+ exports.validateFundDefinition = exports.summarizeFundFinalityPayload = exports.summarizeFundClosingDescriptor = exports.summarizeDistributionDescriptor = exports.summarizeLPPositionReceipt = exports.summarizeCapitalCallState = exports.summarizeFundDefinition = exports.validateBondSettlementMatchesExpected = exports.validateBondSettlementDescriptor = exports.summarizeBondSettlementDescriptor = exports.verifyBondIssuanceHistory = exports.summarizeBondIssuanceState = exports.buildRedeemedBondIssuanceState = exports.validateBondStateTransition = exports.validateBondCrossChecks = exports.validateBondIssuanceState = exports.validateBondDefinition = exports.exportReceivableFinalityPayload = exports.exportReceivableEvidence = exports.verifyReceivableStateHistory = exports.verifyReceivableClosing = exports.prepareReceivableClosing = exports.verifyReceivableWriteOff = exports.prepareReceivableWriteOff = exports.verifyReceivableRepaymentClaim = exports.executeReceivableRepaymentClaim = exports.inspectReceivableRepaymentClaim = exports.prepareReceivableRepaymentClaim = exports.verifyReceivableRepayment = exports.prepareReceivableRepayment = exports.verifyReceivableFundingClaim = exports.executeReceivableFundingClaim = exports.inspectReceivableFundingClaim = exports.prepareReceivableFundingClaim = exports.verifyReceivableFunding = exports.prepareReceivableFunding = exports.loadReceivable = exports.verifyReceivable = exports.defineReceivable = exports.exportFundFinalityPayload = exports.exportFundEvidence = exports.verifyFundClosing = exports.prepareFundClosing = exports.verifyDistribution = exports.executeDistributionClaim = exports.inspectDistributionClaim = exports.reconcilePosition = exports.prepareDistribution = exports.verifyPositionReceiptChain = exports.verifyPositionReceipt = void 0;
19
+ exports.verifyState = exports.inspectTransfer = exports.executeTransfer = exports.prepareTransfer = exports.issue = exports.validatePolicyTemplateParams = exports.describePolicyTemplate = exports.validatePolicyTemplateManifest = exports.loadPolicyTemplateManifest = exports.listPolicyTemplates = exports.buildPolicyOutputDescriptor = exports.compilePolicyStateContract = exports.verifyReceivableStateHistoryValidation = exports.validateReceivableWriteOffTransition = exports.validateReceivableRepaymentTransition = exports.validateReceivableFundingTransition = exports.validateReceivableCrossChecks = exports.validateReceivableState = exports.validateReceivableRepaymentClaimDescriptor = exports.validateReceivableRepaymentClaimAgainstState = exports.validateReceivableFundingClaimDescriptor = exports.validateReceivableFundingClaimAgainstState = exports.validateReceivableDefinition = exports.validateReceivableClosingDescriptor = exports.validateReceivableClosingAgainstState = exports.summarizeReceivableState = exports.summarizeReceivableRepaymentClaimDescriptor = exports.summarizeReceivableFundingClaimDescriptor = exports.summarizeReceivableDefinition = exports.summarizeReceivableClosingDescriptor = exports.buildReceivableRepaymentClaimDescriptor = exports.buildReceivableFundingClaimDescriptor = exports.buildReceivableClosingDescriptor = exports.buildFundedReceivableState = exports.buildDefaultedReceivableState = exports.applyReceivableRepayment = exports.buildFundClosingDescriptor = exports.buildDistributionDescriptor = exports.applyDistributionsToReceipt = exports.applyDistributionToReceipt = exports.buildLPPositionReceipt = exports.buildRefundedCapitalCallState = exports.buildClaimedCapitalCallState = exports.validateClosingAgainstReceipt = exports.validateDistributionAgainstReceipt = exports.validateFundCrossChecks = exports.validateFundClosingDescriptor = exports.validateDistributionDescriptor = exports.validateLPPositionReceipt = exports.validateCapitalCallState = void 0;
20
+ exports.validatePolicyTransferDescriptor = exports.validatePolicyOutputDescriptor = exports.validatePolicyState = exports.summarizePolicyTransferDescriptor = exports.summarizePolicyOutputDescriptor = exports.summarizePolicyState = exports.exportPolicyEvidence = exports.verifyTransfer = void 0;
21
21
  var SimplicityClient_1 = require("./client/SimplicityClient");
22
22
  Object.defineProperty(exports, "createSimplicityClient", { enumerable: true, get: function () { return SimplicityClient_1.createSimplicityClient; } });
23
23
  Object.defineProperty(exports, "SimplicityClient", { enumerable: true, get: function () { return SimplicityClient_1.SimplicityClient; } });
@@ -27,6 +27,9 @@ var DeployedContract_1 = require("./client/DeployedContract");
27
27
  Object.defineProperty(exports, "DeployedContract", { enumerable: true, get: function () { return DeployedContract_1.DeployedContract; } });
28
28
  var RelayerClient_1 = require("./gasless/RelayerClient");
29
29
  Object.defineProperty(exports, "RelayerClient", { enumerable: true, get: function () { return RelayerClient_1.RelayerClient; } });
30
+ var rpc_1 = require("./core/rpc");
31
+ Object.defineProperty(exports, "ElementsRpcClient", { enumerable: true, get: function () { return rpc_1.ElementsRpcClient; } });
32
+ __exportStar(require("./x402"), exports);
30
33
  __exportStar(require("./core/types"), exports);
31
34
  __exportStar(require("./core/errors"), exports);
32
35
  var presets_1 = require("./core/presets");
@@ -0,0 +1,125 @@
1
+ import { ElementsRpcClient } from "../core/rpc";
2
+ export declare const LIQUID_X402_SCHEME: "exact-liquid-pset";
3
+ export declare const LIQUID_X402_VERSION: 1;
4
+ export declare const LIQUID_X402_DEFAULT_NETWORK: "liquidtestnet";
5
+ export declare const LIQUID_X402_DEFAULT_TIMEOUT_SECONDS = 60;
6
+ export type LiquidX402Network = "liquidtestnet" | "liquidv1";
7
+ export type LiquidX402AssetKey = "lbtc" | "usdt";
8
+ export interface LiquidX402Asset {
9
+ key: LiquidX402AssetKey;
10
+ label: string;
11
+ network: LiquidX402Network;
12
+ assetId: string;
13
+ decimals: number;
14
+ isNative: boolean;
15
+ }
16
+ export interface LiquidX402RequirementsInput {
17
+ paymentRequestId: string;
18
+ resource: string;
19
+ payTo: string;
20
+ amountAtomic: string | number | bigint;
21
+ network?: LiquidX402Network;
22
+ asset?: LiquidX402AssetKey | string;
23
+ description?: string;
24
+ mimeType?: string;
25
+ maxTimeoutSeconds?: number;
26
+ expiresAt?: string | Date;
27
+ maxFeeSat?: string | number | bigint;
28
+ metadata?: Record<string, unknown>;
29
+ }
30
+ export interface LiquidX402PaymentRequirements {
31
+ scheme: typeof LIQUID_X402_SCHEME;
32
+ network: LiquidX402Network;
33
+ maxAmountRequired: string;
34
+ resource: string;
35
+ description: string;
36
+ mimeType: string;
37
+ payTo: string;
38
+ maxTimeoutSeconds: number;
39
+ asset: string;
40
+ extra: {
41
+ paymentRequestId: string;
42
+ asset: LiquidX402AssetKey;
43
+ assetId: string;
44
+ decimals: number;
45
+ expiresAt: string;
46
+ feeAsset: "lbtc";
47
+ feeAssetId?: string;
48
+ maxFeeSat?: string;
49
+ metadata?: Record<string, unknown>;
50
+ };
51
+ }
52
+ export interface LiquidX402PaymentPayload {
53
+ scheme: typeof LIQUID_X402_SCHEME;
54
+ network: LiquidX402Network;
55
+ paymentRequestId: string;
56
+ asset: LiquidX402AssetKey;
57
+ assetId: string;
58
+ amountAtomic: string;
59
+ payTo: string;
60
+ psetBase64: string;
61
+ summaryHash: string;
62
+ payer?: string;
63
+ expiresAt: string;
64
+ }
65
+ export interface LiquidX402PreparePsetPaymentInput {
66
+ requirements: LiquidX402PaymentRequirements;
67
+ wallet: string;
68
+ payer?: string;
69
+ locktime?: number;
70
+ sign?: boolean;
71
+ }
72
+ export interface LiquidX402PreparePsetPaymentResult {
73
+ paymentPayload: LiquidX402PaymentPayload;
74
+ xPayment: string;
75
+ psetBase64: string;
76
+ summaryHash: string;
77
+ }
78
+ export interface LiquidX402VerifyPaymentInput {
79
+ requirements: LiquidX402PaymentRequirements | Record<string, unknown>;
80
+ paymentPayload: LiquidX402PaymentPayload | Record<string, unknown>;
81
+ now?: Date;
82
+ }
83
+ export interface LiquidX402VerifyPaymentResult {
84
+ isValid: boolean;
85
+ invalidReason?: string;
86
+ payer?: string | null;
87
+ network?: LiquidX402Network;
88
+ paymentRequestId?: string;
89
+ summaryHash?: string;
90
+ }
91
+ export interface LiquidX402SettlePaymentInput extends LiquidX402VerifyPaymentInput {
92
+ wallet?: string;
93
+ broadcast?: boolean;
94
+ }
95
+ export interface LiquidX402SettlePaymentResult {
96
+ success: boolean;
97
+ errorCode?: string;
98
+ txId?: string;
99
+ transactionHash?: string;
100
+ rawTxHex?: string;
101
+ summaryHash?: string;
102
+ }
103
+ type DecodePsbtResult = {
104
+ fees?: Record<string, number>;
105
+ outputs?: Array<{
106
+ amount?: number;
107
+ asset?: string;
108
+ script?: {
109
+ address?: string;
110
+ hex?: string;
111
+ };
112
+ }>;
113
+ };
114
+ export declare const LIQUID_X402_ASSETS: Record<LiquidX402Network, Record<LiquidX402AssetKey, LiquidX402Asset>>;
115
+ export declare function listLiquidX402Assets(network?: LiquidX402Network): LiquidX402Asset[];
116
+ export declare function resolveLiquidX402Asset(asset: LiquidX402AssetKey | string, network?: LiquidX402Network): LiquidX402Asset;
117
+ export declare function buildLiquidX402Requirements(input: LiquidX402RequirementsInput): LiquidX402PaymentRequirements;
118
+ export declare function encodeLiquidXPayment(payload: LiquidX402PaymentPayload): string;
119
+ export declare function decodeLiquidXPayment(raw: string): LiquidX402PaymentPayload | null;
120
+ export declare function prepareLiquidX402PsetPayment(rpc: ElementsRpcClient, input: LiquidX402PreparePsetPaymentInput): Promise<LiquidX402PreparePsetPaymentResult>;
121
+ export declare function verifyLiquidX402Payment(rpc: ElementsRpcClient | null, input: LiquidX402VerifyPaymentInput): Promise<LiquidX402VerifyPaymentResult>;
122
+ export declare function settleLiquidX402Payment(rpc: ElementsRpcClient, input: LiquidX402SettlePaymentInput): Promise<LiquidX402SettlePaymentResult>;
123
+ export declare function verifyLiquidX402PayloadFields(requirements: LiquidX402PaymentRequirements | Record<string, unknown>, payload: LiquidX402PaymentPayload | Record<string, unknown>, now?: Date): LiquidX402VerifyPaymentResult;
124
+ export declare function buildLiquidPsetSummaryHash(decoded: DecodePsbtResult, requirements: LiquidX402PaymentRequirements | Record<string, unknown>): string;
125
+ export {};
@@ -0,0 +1,396 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LIQUID_X402_ASSETS = exports.LIQUID_X402_DEFAULT_TIMEOUT_SECONDS = exports.LIQUID_X402_DEFAULT_NETWORK = exports.LIQUID_X402_VERSION = exports.LIQUID_X402_SCHEME = void 0;
4
+ exports.listLiquidX402Assets = listLiquidX402Assets;
5
+ exports.resolveLiquidX402Asset = resolveLiquidX402Asset;
6
+ exports.buildLiquidX402Requirements = buildLiquidX402Requirements;
7
+ exports.encodeLiquidXPayment = encodeLiquidXPayment;
8
+ exports.decodeLiquidXPayment = decodeLiquidXPayment;
9
+ exports.prepareLiquidX402PsetPayment = prepareLiquidX402PsetPayment;
10
+ exports.verifyLiquidX402Payment = verifyLiquidX402Payment;
11
+ exports.settleLiquidX402Payment = settleLiquidX402Payment;
12
+ exports.verifyLiquidX402PayloadFields = verifyLiquidX402PayloadFields;
13
+ exports.buildLiquidPsetSummaryHash = buildLiquidPsetSummaryHash;
14
+ const node_crypto_1 = require("node:crypto");
15
+ exports.LIQUID_X402_SCHEME = "exact-liquid-pset";
16
+ exports.LIQUID_X402_VERSION = 1;
17
+ exports.LIQUID_X402_DEFAULT_NETWORK = "liquidtestnet";
18
+ exports.LIQUID_X402_DEFAULT_TIMEOUT_SECONDS = 60;
19
+ const LIQUID_TESTNET_USDT_ASSET_ID = "b612eb46313a2cd6ebabd8b7a8eed5696e29898b87a43bff41c94f51acef9d73";
20
+ const LIQUID_MAINNET_USDT_ASSET_ID = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2";
21
+ exports.LIQUID_X402_ASSETS = {
22
+ liquidtestnet: {
23
+ lbtc: {
24
+ key: "lbtc",
25
+ label: "Liquid Bitcoin",
26
+ network: "liquidtestnet",
27
+ assetId: "bitcoin",
28
+ decimals: 8,
29
+ isNative: true,
30
+ },
31
+ usdt: {
32
+ key: "usdt",
33
+ label: "Tether USDt",
34
+ network: "liquidtestnet",
35
+ assetId: LIQUID_TESTNET_USDT_ASSET_ID,
36
+ decimals: 8,
37
+ isNative: false,
38
+ },
39
+ },
40
+ liquidv1: {
41
+ lbtc: {
42
+ key: "lbtc",
43
+ label: "Liquid Bitcoin",
44
+ network: "liquidv1",
45
+ assetId: "bitcoin",
46
+ decimals: 8,
47
+ isNative: true,
48
+ },
49
+ usdt: {
50
+ key: "usdt",
51
+ label: "Tether USDt",
52
+ network: "liquidv1",
53
+ assetId: LIQUID_MAINNET_USDT_ASSET_ID,
54
+ decimals: 8,
55
+ isNative: false,
56
+ },
57
+ },
58
+ };
59
+ function listLiquidX402Assets(network) {
60
+ if (network)
61
+ return Object.values(exports.LIQUID_X402_ASSETS[network]);
62
+ return Object.values(exports.LIQUID_X402_ASSETS).flatMap((assets) => Object.values(assets));
63
+ }
64
+ function resolveLiquidX402Asset(asset, network = exports.LIQUID_X402_DEFAULT_NETWORK) {
65
+ const key = normalizeAssetKey(asset);
66
+ const resolved = exports.LIQUID_X402_ASSETS[network]?.[key];
67
+ if (!resolved) {
68
+ throw new Error(`unsupported Liquid x402 asset: ${asset} on ${network}`);
69
+ }
70
+ return resolved;
71
+ }
72
+ function buildLiquidX402Requirements(input) {
73
+ const network = normalizeNetwork(input.network ?? exports.LIQUID_X402_DEFAULT_NETWORK);
74
+ const asset = resolveLiquidX402Asset(input.asset ?? "usdt", network);
75
+ const amountAtomic = normalizeAmountAtomic(input.amountAtomic);
76
+ const expiresAt = normalizeExpiresAt(input.expiresAt, input.maxTimeoutSeconds);
77
+ const description = String(input.description ?? "").trim() || "Unlock resource";
78
+ const mimeType = String(input.mimeType ?? "").trim() || "application/octet-stream";
79
+ const maxTimeoutSeconds = normalizeTimeout(input.maxTimeoutSeconds);
80
+ const paymentRequestId = String(input.paymentRequestId ?? "").trim();
81
+ if (!paymentRequestId)
82
+ throw new Error("paymentRequestId is required");
83
+ const resource = String(input.resource ?? "").trim();
84
+ if (!resource)
85
+ throw new Error("resource is required");
86
+ const payTo = String(input.payTo ?? "").trim();
87
+ if (!payTo)
88
+ throw new Error("payTo is required");
89
+ return {
90
+ scheme: exports.LIQUID_X402_SCHEME,
91
+ network,
92
+ maxAmountRequired: amountAtomic,
93
+ resource,
94
+ description,
95
+ mimeType,
96
+ payTo,
97
+ maxTimeoutSeconds,
98
+ asset: asset.assetId,
99
+ extra: {
100
+ paymentRequestId,
101
+ asset: asset.key,
102
+ assetId: asset.assetId,
103
+ decimals: asset.decimals,
104
+ expiresAt,
105
+ feeAsset: "lbtc",
106
+ feeAssetId: exports.LIQUID_X402_ASSETS[network].lbtc.assetId,
107
+ ...(input.maxFeeSat !== undefined ? { maxFeeSat: normalizeAmountAtomic(input.maxFeeSat) } : {}),
108
+ ...(input.metadata ? { metadata: input.metadata } : {}),
109
+ },
110
+ };
111
+ }
112
+ function encodeLiquidXPayment(payload) {
113
+ return Buffer.from(JSON.stringify(payload)).toString("base64url");
114
+ }
115
+ function decodeLiquidXPayment(raw) {
116
+ const value = String(raw ?? "").trim();
117
+ if (!value)
118
+ return null;
119
+ try {
120
+ const parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
121
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
122
+ return null;
123
+ if (String(parsed.scheme ?? "") !== exports.LIQUID_X402_SCHEME)
124
+ return null;
125
+ return parsed;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ async function prepareLiquidX402PsetPayment(rpc, input) {
132
+ const requirements = coerceRequirements(input.requirements);
133
+ const amount = atomicToDecimalNumber(requirements.maxAmountRequired, requirements.extra.decimals);
134
+ const outputs = [
135
+ { [requirements.payTo]: amount, asset: requirements.asset },
136
+ ];
137
+ const pset = await rpc.call("createpsbt", [[], outputs, input.locktime ?? 0, true], input.wallet);
138
+ const updatedPset = await rpc.call("utxoupdatepsbt", [pset], input.wallet);
139
+ const signed = input.sign === false
140
+ ? updatedPset
141
+ : (await rpc.call("walletprocesspsbt", [updatedPset, true, "ALL", true], input.wallet)).psbt ?? updatedPset;
142
+ const decoded = await rpc.call("decodepsbt", [signed], input.wallet);
143
+ const summaryHash = buildLiquidPsetSummaryHash(decoded, requirements);
144
+ const paymentPayload = {
145
+ scheme: exports.LIQUID_X402_SCHEME,
146
+ network: requirements.network,
147
+ paymentRequestId: requirements.extra.paymentRequestId,
148
+ asset: requirements.extra.asset,
149
+ assetId: requirements.asset,
150
+ amountAtomic: requirements.maxAmountRequired,
151
+ payTo: requirements.payTo,
152
+ psetBase64: signed,
153
+ summaryHash,
154
+ ...(input.payer ? { payer: input.payer } : {}),
155
+ expiresAt: requirements.extra.expiresAt,
156
+ };
157
+ return {
158
+ paymentPayload,
159
+ xPayment: encodeLiquidXPayment(paymentPayload),
160
+ psetBase64: signed,
161
+ summaryHash,
162
+ };
163
+ }
164
+ async function verifyLiquidX402Payment(rpc, input) {
165
+ const requirements = coerceRequirements(input.requirements);
166
+ const payload = coercePaymentPayload(input.paymentPayload);
167
+ const basic = verifyLiquidX402PayloadFields(requirements, payload, input.now);
168
+ if (!basic.isValid)
169
+ return basic;
170
+ if (!rpc) {
171
+ return basic;
172
+ }
173
+ try {
174
+ const decoded = await rpc.call("decodepsbt", [payload.psetBase64]);
175
+ const actualSummaryHash = buildLiquidPsetSummaryHash(decoded, requirements);
176
+ if (actualSummaryHash !== payload.summaryHash) {
177
+ return { ...basic, isValid: false, invalidReason: "pset_summary_mismatch" };
178
+ }
179
+ if (!decodedContainsExpectedOutput(decoded, requirements)) {
180
+ return { ...basic, isValid: false, invalidReason: "pset_expected_output_missing" };
181
+ }
182
+ if (!decodedFeeWithinCap(decoded, requirements)) {
183
+ return { ...basic, isValid: false, invalidReason: "fee_too_high" };
184
+ }
185
+ return basic;
186
+ }
187
+ catch {
188
+ return { ...basic, isValid: false, invalidReason: "pset_decode_failed" };
189
+ }
190
+ }
191
+ async function settleLiquidX402Payment(rpc, input) {
192
+ const verification = await verifyLiquidX402Payment(rpc, input);
193
+ if (!verification.isValid) {
194
+ return { success: false, errorCode: verification.invalidReason ?? "payment_verification_failed" };
195
+ }
196
+ const payload = coercePaymentPayload(input.paymentPayload);
197
+ try {
198
+ const finalized = await rpc.call("finalizepsbt", [payload.psetBase64, true], input.wallet);
199
+ if (!finalized.complete || !finalized.hex) {
200
+ return { success: false, errorCode: "pset_not_complete", summaryHash: payload.summaryHash };
201
+ }
202
+ const mempool = await rpc.call("testmempoolaccept", [[finalized.hex]], input.wallet);
203
+ if (mempool[0]?.allowed !== true) {
204
+ return {
205
+ success: false,
206
+ errorCode: mempool[0]?.reject_reason || "mempool_rejected",
207
+ rawTxHex: finalized.hex,
208
+ summaryHash: payload.summaryHash,
209
+ };
210
+ }
211
+ if (input.broadcast === false) {
212
+ return { success: true, rawTxHex: finalized.hex, summaryHash: payload.summaryHash };
213
+ }
214
+ const txId = await rpc.call("sendrawtransaction", [finalized.hex], input.wallet);
215
+ return {
216
+ success: true,
217
+ txId,
218
+ transactionHash: txId,
219
+ rawTxHex: finalized.hex,
220
+ summaryHash: payload.summaryHash,
221
+ };
222
+ }
223
+ catch {
224
+ return { success: false, errorCode: "settlement_rpc_failed", summaryHash: payload.summaryHash };
225
+ }
226
+ }
227
+ function verifyLiquidX402PayloadFields(requirements, payload, now = new Date()) {
228
+ const req = coerceRequirements(requirements);
229
+ const parsed = coercePaymentPayload(payload);
230
+ const base = {
231
+ payer: parsed.payer ?? null,
232
+ network: parsed.network,
233
+ paymentRequestId: parsed.paymentRequestId,
234
+ summaryHash: parsed.summaryHash,
235
+ };
236
+ if (parsed.scheme !== exports.LIQUID_X402_SCHEME)
237
+ return { ...base, isValid: false, invalidReason: "unsupported_scheme" };
238
+ if (parsed.network !== req.network)
239
+ return { ...base, isValid: false, invalidReason: "network_mismatch" };
240
+ if (parsed.paymentRequestId !== req.extra.paymentRequestId) {
241
+ return { ...base, isValid: false, invalidReason: "payment_request_mismatch" };
242
+ }
243
+ if (parsed.asset !== req.extra.asset || parsed.assetId !== req.asset) {
244
+ return { ...base, isValid: false, invalidReason: "asset_mismatch" };
245
+ }
246
+ if (parsed.amountAtomic !== req.maxAmountRequired) {
247
+ return { ...base, isValid: false, invalidReason: "amount_mismatch" };
248
+ }
249
+ if (parsed.payTo !== req.payTo)
250
+ return { ...base, isValid: false, invalidReason: "recipient_mismatch" };
251
+ if (!parsed.psetBase64)
252
+ return { ...base, isValid: false, invalidReason: "pset_missing" };
253
+ if (!parsed.summaryHash)
254
+ return { ...base, isValid: false, invalidReason: "summary_hash_missing" };
255
+ if (new Date(parsed.expiresAt).getTime() <= now.getTime()) {
256
+ return { ...base, isValid: false, invalidReason: "payment_expired" };
257
+ }
258
+ return { ...base, isValid: true };
259
+ }
260
+ function buildLiquidPsetSummaryHash(decoded, requirements) {
261
+ const req = coerceRequirements(requirements);
262
+ return sha256Hex(stableStringify({
263
+ scheme: exports.LIQUID_X402_SCHEME,
264
+ network: req.network,
265
+ paymentRequestId: req.extra.paymentRequestId,
266
+ asset: req.extra.asset,
267
+ assetId: req.asset,
268
+ amountAtomic: req.maxAmountRequired,
269
+ payTo: req.payTo,
270
+ outputs: normalizeDecodedOutputs(decoded),
271
+ fees: decoded.fees ?? {},
272
+ }));
273
+ }
274
+ function decodedContainsExpectedOutput(decoded, requirements) {
275
+ const expectedAmount = atomicToDecimalNumber(requirements.maxAmountRequired, requirements.extra.decimals);
276
+ return (decoded.outputs ?? []).some((output) => (String(output.asset ?? "").toLowerCase() === requirements.asset.toLowerCase() &&
277
+ Math.round(Number(output.amount ?? 0) * 10 ** requirements.extra.decimals) ===
278
+ Math.round(expectedAmount * 10 ** requirements.extra.decimals) &&
279
+ String(output.script?.address ?? "") === requirements.payTo));
280
+ }
281
+ function normalizeDecodedOutputs(decoded) {
282
+ return (decoded.outputs ?? []).map((output) => ({
283
+ amount: output.amount ?? null,
284
+ asset: output.asset ?? null,
285
+ address: output.script?.address ?? null,
286
+ scriptPubKey: output.script?.hex ?? null,
287
+ }));
288
+ }
289
+ function coerceRequirements(value) {
290
+ if (!value || typeof value !== "object" || Array.isArray(value))
291
+ throw new Error("requirements must be an object");
292
+ const raw = value;
293
+ const extra = raw.extra && typeof raw.extra === "object" && !Array.isArray(raw.extra) ? raw.extra : {};
294
+ const network = normalizeNetwork(raw.network);
295
+ const asset = resolveLiquidX402Asset(extra.asset ?? raw.asset, network);
296
+ return {
297
+ scheme: exports.LIQUID_X402_SCHEME,
298
+ network,
299
+ maxAmountRequired: normalizeAmountAtomic(raw.maxAmountRequired),
300
+ resource: String(raw.resource ?? ""),
301
+ description: String(raw.description ?? ""),
302
+ mimeType: String(raw.mimeType ?? ""),
303
+ payTo: String(raw.payTo ?? ""),
304
+ maxTimeoutSeconds: normalizeTimeout(raw.maxTimeoutSeconds),
305
+ asset: String(raw.asset ?? extra.assetId ?? asset.assetId),
306
+ extra: {
307
+ paymentRequestId: String(extra.paymentRequestId ?? raw.paymentRequestId ?? ""),
308
+ asset: asset.key,
309
+ assetId: String(extra.assetId ?? raw.asset ?? asset.assetId),
310
+ decimals: Number(extra.decimals ?? asset.decimals),
311
+ expiresAt: String(extra.expiresAt ?? ""),
312
+ feeAsset: "lbtc",
313
+ feeAssetId: String(extra.feeAssetId ?? exports.LIQUID_X402_ASSETS[network].lbtc.assetId),
314
+ ...(extra.maxFeeSat !== undefined ? { maxFeeSat: normalizeAmountAtomic(extra.maxFeeSat) } : {}),
315
+ ...(extra.metadata ? { metadata: extra.metadata } : {}),
316
+ },
317
+ };
318
+ }
319
+ function decodedFeeWithinCap(decoded, requirements) {
320
+ if (requirements.extra.maxFeeSat === undefined)
321
+ return true;
322
+ const maxFeeSat = BigInt(requirements.extra.maxFeeSat);
323
+ const feeSat = Object.values(decoded.fees ?? {}).reduce((sum, amount) => {
324
+ const sat = Math.round(Number(amount) * 100_000_000);
325
+ return sum + BigInt(Number.isFinite(sat) ? sat : 0);
326
+ }, 0n);
327
+ return feeSat <= maxFeeSat;
328
+ }
329
+ function coercePaymentPayload(value) {
330
+ if (!value || typeof value !== "object" || Array.isArray(value))
331
+ throw new Error("payment payload must be an object");
332
+ const raw = value;
333
+ return {
334
+ scheme: exports.LIQUID_X402_SCHEME,
335
+ network: normalizeNetwork(raw.network),
336
+ paymentRequestId: String(raw.paymentRequestId ?? ""),
337
+ asset: normalizeAssetKey(String(raw.asset ?? "")),
338
+ assetId: String(raw.assetId ?? ""),
339
+ amountAtomic: normalizeAmountAtomic(raw.amountAtomic),
340
+ payTo: String(raw.payTo ?? ""),
341
+ psetBase64: String(raw.psetBase64 ?? ""),
342
+ summaryHash: String(raw.summaryHash ?? ""),
343
+ ...(raw.payer ? { payer: String(raw.payer) } : {}),
344
+ expiresAt: String(raw.expiresAt ?? ""),
345
+ };
346
+ }
347
+ function normalizeNetwork(input) {
348
+ const value = String(input ?? "").trim().toLowerCase();
349
+ if (value === "liquidtestnet" || value === "liquidv1")
350
+ return value;
351
+ throw new Error(`unsupported Liquid x402 network: ${String(input)}`);
352
+ }
353
+ function normalizeAssetKey(input) {
354
+ const value = String(input ?? "").trim().toLowerCase();
355
+ if (value === "lbtc" || value === "bitcoin")
356
+ return "lbtc";
357
+ if (value === "usdt" || value === "usdt-liquid" || value === "tether")
358
+ return "usdt";
359
+ throw new Error(`unsupported Liquid x402 asset: ${String(input)}`);
360
+ }
361
+ function normalizeAmountAtomic(input) {
362
+ const raw = typeof input === "bigint" ? input.toString() : String(input ?? "").trim();
363
+ if (!/^\d+$/u.test(raw))
364
+ throw new Error("amountAtomic must be an integer string");
365
+ return BigInt(raw).toString();
366
+ }
367
+ function normalizeTimeout(input) {
368
+ const parsed = Number(input ?? exports.LIQUID_X402_DEFAULT_TIMEOUT_SECONDS);
369
+ return Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : exports.LIQUID_X402_DEFAULT_TIMEOUT_SECONDS;
370
+ }
371
+ function normalizeExpiresAt(expiresAt, timeoutSeconds) {
372
+ if (expiresAt instanceof Date)
373
+ return expiresAt.toISOString();
374
+ const raw = String(expiresAt ?? "").trim();
375
+ if (raw)
376
+ return new Date(raw).toISOString();
377
+ return new Date(Date.now() + normalizeTimeout(timeoutSeconds) * 1000).toISOString();
378
+ }
379
+ function atomicToDecimalNumber(amountAtomic, decimals) {
380
+ const amount = BigInt(amountAtomic);
381
+ const scale = 10n ** BigInt(decimals);
382
+ const whole = amount / scale;
383
+ const frac = amount % scale;
384
+ return Number(`${whole}.${frac.toString().padStart(decimals, "0")}`);
385
+ }
386
+ function sha256Hex(value) {
387
+ return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex");
388
+ }
389
+ function stableStringify(value) {
390
+ if (value === null || typeof value !== "object")
391
+ return JSON.stringify(value);
392
+ if (Array.isArray(value))
393
+ return `[${value.map((entry) => stableStringify(entry)).join(",")}]`;
394
+ const record = value;
395
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(",")}}`;
396
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hazbase/simplicity",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "An SDK for Simplicity on Liquid",
5
5
  "author": "IndieSquare Inc <info@hazbase.com>",
6
6
  "keywords": [