@hazbase/simplicity 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -2
- package/dist/domain/rwaDvp.d.ts +2 -0
- package/dist/domain/rwaDvp.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/x402/atomicDvp.d.ts +197 -0
- package/dist/x402/atomicDvp.js +482 -0
- package/dist/x402/index.d.ts +1 -0
- package/dist/x402/index.js +15 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,20 +20,25 @@ With the current public SDK you can build and test:
|
|
|
20
20
|
- bond redemption / settlement / close-out flows
|
|
21
21
|
- LP fund capital call / distribution / close-out flows
|
|
22
22
|
- receivable repayment-first funding / partial repayment / closing flows
|
|
23
|
+
- RWA delivery-versus-payment flows over Liquid PSETs and Liquid x402
|
|
24
|
+
- atomic Liquid DvP proposals where service delivery and buyer payment settle in one PSET
|
|
23
25
|
- evidence, trust summary, lineage, and finality exports
|
|
24
26
|
|
|
25
27
|
## Public Architecture
|
|
26
28
|
|
|
27
|
-
The public SDK is organized into
|
|
29
|
+
The public SDK is organized into domain clients and lower-level payment helpers:
|
|
28
30
|
- `sdk.outputBinding`: shared output-binding support, evaluation, and fallback behavior
|
|
29
31
|
- `sdk.policies`: generic constrained transfer and recursive policy engine
|
|
30
32
|
- `sdk.bonds`: private bond / credit settlement business layer
|
|
31
33
|
- `sdk.funds`: LP fund settlement business layer
|
|
32
34
|
- `sdk.receivables`: repayment-first receivable business layer
|
|
35
|
+
- `sdk.rwaDvp`: RWA purchase terms, payment requirements, claim descriptors, and evidence
|
|
36
|
+
- `sdk.payments.x402`: Liquid x402 assets, PSET payment helpers, verification, and settlement
|
|
33
37
|
|
|
34
38
|
A useful mental model is:
|
|
35
39
|
- `sdk.outputBinding` + `sdk.policies` provide the shared settlement kernel
|
|
36
|
-
- `sdk.bonds`, `sdk.funds`, and `sdk.
|
|
40
|
+
- `sdk.bonds`, `sdk.funds`, `sdk.receivables`, and `sdk.rwaDvp` build domain flows on top of that kernel
|
|
41
|
+
- `sdk.payments.x402` and the root-level `x402` exports provide the Liquid PSET payment layer used by those flows
|
|
37
42
|
|
|
38
43
|
## Quickstart
|
|
39
44
|
|
|
@@ -158,6 +163,12 @@ Use `sdk.rwaDvp` when a purchase flow needs a Liquid PSET payment request,
|
|
|
158
163
|
delivery/refund claim descriptors, and an evidence bundle that ties the Liquid
|
|
159
164
|
payment and delivery to an external lock or allocation record.
|
|
160
165
|
|
|
166
|
+
The EVM-side lock reference can describe the source asset being held for
|
|
167
|
+
settlement. Set `evmLock.tokenStandard` to `"ERC3475"`, `"ERC20"`, `"ERC721"`,
|
|
168
|
+
or `"ERC1155"` and include the token address / id fields used by your lock
|
|
169
|
+
manager. Existing callers that omit `tokenStandard` are treated as `"ERC3475"`
|
|
170
|
+
for backwards compatibility.
|
|
171
|
+
|
|
161
172
|
For standard Liquid assets, `payment.asset` can be `"lbtc"` or `"usdt"`. If a
|
|
162
173
|
testnet issuer or deployment uses a different USDt asset id, set
|
|
163
174
|
`payment.asset: "usdt"` and pass the explicit `payment.assetId`; the generated
|
|
@@ -192,6 +203,81 @@ delivery/refund output checks are the practical default; descriptor-bound checks
|
|
|
192
203
|
should be used only when the caller can provide the exact output data required
|
|
193
204
|
by the descriptor.
|
|
194
205
|
|
|
206
|
+
#### Atomic Liquid DvP PSET helpers
|
|
207
|
+
|
|
208
|
+
For flows that should avoid a separate "buyer pays first, service delivers
|
|
209
|
+
later" step, the SDK also exposes lower-level atomic DvP helpers from the root
|
|
210
|
+
package:
|
|
211
|
+
|
|
212
|
+
- `buildLiquidAtomicDvpRequirements(...)`
|
|
213
|
+
- `prepareLiquidAtomicDvpLwkWasmMakerProposal(...)`
|
|
214
|
+
- `prepareLiquidAtomicDvpLwkWasmTakerPayment(...)`
|
|
215
|
+
- `buildLiquidAtomicDvpPaymentFromPset(...)`
|
|
216
|
+
- `verifyLiquidAtomicDvpPayment(...)`
|
|
217
|
+
- `encodeLiquidAtomicDvpPayment(...)`
|
|
218
|
+
- `decodeLiquidAtomicDvpPayment(...)`
|
|
219
|
+
|
|
220
|
+
These helpers model a Liquidex-style exchange:
|
|
221
|
+
- the service/maker selects an exact RWA delivery UTXO and creates a proposal
|
|
222
|
+
- the buyer/taker adds the required payment output and signs the combined PSET
|
|
223
|
+
- the resulting `X-PAYMENT` payload commits to both the payment output and the
|
|
224
|
+
delivery output through a summary hash
|
|
225
|
+
|
|
226
|
+
The LWK convenience helpers dynamically load `lwk_node` or `lwk_wasm` from the
|
|
227
|
+
consuming application. Install one of them in the application that prepares or
|
|
228
|
+
takes proposals:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npm install lwk_node
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Typical server-side shape:
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import {
|
|
238
|
+
buildLiquidAtomicDvpRequirements,
|
|
239
|
+
prepareLiquidAtomicDvpLwkWasmMakerProposal,
|
|
240
|
+
verifyLiquidAtomicDvpPayment,
|
|
241
|
+
} from "@hazbase/simplicity";
|
|
242
|
+
|
|
243
|
+
const requirements = buildLiquidAtomicDvpRequirements({
|
|
244
|
+
network: "liquidtestnet",
|
|
245
|
+
resource: "/v1/orders/<order-id>/liquid-atomic-pset",
|
|
246
|
+
paymentToTreasury: {
|
|
247
|
+
assetId: "<lbtc-or-usdt-asset-id>",
|
|
248
|
+
amountAtomic: "10000",
|
|
249
|
+
recipient: "<treasury-confidential-address>",
|
|
250
|
+
},
|
|
251
|
+
rwaToBuyer: {
|
|
252
|
+
assetId: "<rwa-liquid-asset-id>",
|
|
253
|
+
amountAtomic: "10",
|
|
254
|
+
recipient: "<buyer-confidential-address>",
|
|
255
|
+
},
|
|
256
|
+
expiresAt: new Date(Date.now() + 15 * 60_000),
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const maker = await prepareLiquidAtomicDvpLwkWasmMakerProposal({
|
|
260
|
+
requirements,
|
|
261
|
+
mnemonic: process.env.SERVICE_LIQUID_MNEMONIC!,
|
|
262
|
+
descriptor: process.env.SERVICE_LIQUID_DESCRIPTOR!,
|
|
263
|
+
electrumUrl: process.env.LIQUID_ELECTRUM_URL!,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Store maker.proposalPsetBase64 with the order/payment requirements.
|
|
267
|
+
// When the buyer submits X-PAYMENT, verify it before broadcasting.
|
|
268
|
+
const verified = verifyLiquidAtomicDvpPayment({
|
|
269
|
+
requirements,
|
|
270
|
+
paymentPayload: buyerPaymentPayload,
|
|
271
|
+
});
|
|
272
|
+
if (!verified.ok) throw new Error(verified.reason);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The SDK-level payload check is intentionally lightweight: it verifies the
|
|
276
|
+
scheme, network, resource, expiry, PSET value, and summary hash. Production
|
|
277
|
+
settlement services should still decode the final PSET with their Liquid node or
|
|
278
|
+
wallet stack, verify the concrete payment and delivery outputs, and only then
|
|
279
|
+
broadcast.
|
|
280
|
+
|
|
195
281
|
## CLI and Confidence Commands
|
|
196
282
|
|
|
197
283
|
### Validation Surface
|
package/dist/domain/rwaDvp.d.ts
CHANGED
|
@@ -7,10 +7,12 @@ export declare const RWA_DVP_REFUND_CLAIM_SCHEMA_VERSION: "rwa-dvp-refund-claim/
|
|
|
7
7
|
export declare const RWA_DVP_VERIFICATION_SCHEMA_VERSION: "rwa-dvp-verification/v1";
|
|
8
8
|
export declare const RWA_DVP_EVIDENCE_SCHEMA_VERSION: "rwa-dvp-evidence/v1";
|
|
9
9
|
export type RwaDvpPaymentAsset = LiquidX402AssetKey;
|
|
10
|
+
export type RwaDvpEvmTokenStandard = "ERC3475" | "ERC20" | "ERC721" | "ERC1155";
|
|
10
11
|
export interface RwaDvpEvmLockReference {
|
|
11
12
|
chainId: number;
|
|
12
13
|
lockManager: string;
|
|
13
14
|
orderKey: string;
|
|
15
|
+
tokenStandard?: RwaDvpEvmTokenStandard;
|
|
14
16
|
token?: string;
|
|
15
17
|
backingOwner?: string;
|
|
16
18
|
classId?: string;
|
package/dist/domain/rwaDvp.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -19,5 +19,5 @@ export { summarizeBondSettlementDescriptor, validateBondSettlementDescriptor, va
|
|
|
19
19
|
export { summarizeFundDefinition, summarizeCapitalCallState, summarizeLPPositionReceipt, summarizeDistributionDescriptor, summarizeFundClosingDescriptor, summarizeFundFinalityPayload, validateFundDefinition, validateCapitalCallState, validateLPPositionReceipt, validateDistributionDescriptor, validateFundClosingDescriptor, validateFundCrossChecks, validateDistributionAgainstReceipt, validateClosingAgainstReceipt, buildClaimedCapitalCallState, buildRefundedCapitalCallState, buildLPPositionReceipt, applyDistributionToReceipt, applyDistributionsToReceipt, buildDistributionDescriptor, buildFundClosingDescriptor, } from "./domain/fundValidation";
|
|
20
20
|
export { applyReceivableRepayment, buildDefaultedReceivableState, buildFundedReceivableState, buildReceivableClosingDescriptor, buildReceivableFundingClaimDescriptor, buildReceivableRepaymentClaimDescriptor, summarizeReceivableClosingDescriptor, summarizeReceivableDefinition, summarizeReceivableFundingClaimDescriptor, summarizeReceivableRepaymentClaimDescriptor, summarizeReceivableState, validateReceivableClosingAgainstState, validateReceivableClosingDescriptor, validateReceivableDefinition, validateReceivableFundingClaimAgainstState, validateReceivableFundingClaimDescriptor, validateReceivableRepaymentClaimAgainstState, validateReceivableRepaymentClaimDescriptor, validateReceivableState, validateReceivableCrossChecks, validateReceivableFundingTransition, validateReceivableRepaymentTransition, validateReceivableWriteOffTransition, verifyReceivableStateHistory as verifyReceivableStateHistoryValidation, } from "./domain/receivableValidation";
|
|
21
21
|
export { RWA_DVP_DELIVERY_CLAIM_SCHEMA_VERSION, RWA_DVP_EVIDENCE_SCHEMA_VERSION, RWA_DVP_PURCHASE_SCHEMA_VERSION, RWA_DVP_REFUND_CLAIM_SCHEMA_VERSION, RWA_DVP_VERIFICATION_SCHEMA_VERSION, buildPaymentRequirements as buildRwaDvpPaymentRequirements, compileEscrowContract as compileRwaDvpEscrowContract, definePurchase as defineRwaDvpPurchase, executeDeliveryClaim as executeRwaDvpDeliveryClaim, executeRefundClaim as executeRwaDvpRefundClaim, exportEvidence as exportRwaDvpEvidence, inspectDeliveryClaim as inspectRwaDvpDeliveryClaim, inspectRefundClaim as inspectRwaDvpRefundClaim, prepareDeliveryClaim as prepareRwaDvpDeliveryClaim, prepareRefundClaim as prepareRwaDvpRefundClaim, summarizePurchase as summarizeRwaDvpPurchase, verifyDeliveryClaim as verifyRwaDvpDeliveryClaim, verifyPaymentPset as verifyRwaDvpPaymentPset, verifyRefundClaim as verifyRwaDvpRefundClaim, } from "./domain/rwaDvp";
|
|
22
|
-
export type { RwaDvpDefinePurchaseInput, RwaDvpClaimOutputBinding, RwaDvpCompiledEscrowContract, RwaDvpCompileEscrowContractInput, RwaDvpDeliveryClaimDescriptor, RwaDvpDeliveryClaimExecution, RwaDvpDeliveryClaimInspection, RwaDvpEvidenceBundle, RwaDvpEvmLockReference, RwaDvpExecuteDeliveryClaimInput, RwaDvpExecuteRefundClaimInput, RwaDvpInspectDeliveryClaimInput, RwaDvpInspectRefundClaimInput, RwaDvpPaymentAsset, RwaDvpPreparedPurchase, RwaDvpPrepareDeliveryClaimInput, RwaDvpPrepareRefundClaimInput, RwaDvpPurchaseDefinition, RwaDvpRefundClaimDescriptor, RwaDvpRefundClaimExecution, RwaDvpRefundClaimInspection, RwaDvpSummary, RwaDvpVerificationReport, } from "./domain/rwaDvp";
|
|
22
|
+
export type { RwaDvpDefinePurchaseInput, RwaDvpClaimOutputBinding, RwaDvpCompiledEscrowContract, RwaDvpCompileEscrowContractInput, RwaDvpDeliveryClaimDescriptor, RwaDvpDeliveryClaimExecution, RwaDvpDeliveryClaimInspection, RwaDvpEvidenceBundle, RwaDvpEvmLockReference, RwaDvpEvmTokenStandard, RwaDvpExecuteDeliveryClaimInput, RwaDvpExecuteRefundClaimInput, RwaDvpInspectDeliveryClaimInput, RwaDvpInspectRefundClaimInput, RwaDvpPaymentAsset, RwaDvpPreparedPurchase, RwaDvpPrepareDeliveryClaimInput, RwaDvpPrepareRefundClaimInput, RwaDvpPurchaseDefinition, RwaDvpRefundClaimDescriptor, RwaDvpRefundClaimExecution, RwaDvpRefundClaimInspection, RwaDvpSummary, RwaDvpVerificationReport, } from "./domain/rwaDvp";
|
|
23
23
|
export { compilePolicyStateContract, buildPolicyOutputDescriptor, listPolicyTemplates, loadPolicyTemplateManifest, validatePolicyTemplateManifest, describePolicyTemplate, validatePolicyTemplateParams, issue, prepareTransfer, executeTransfer, inspectTransfer, verifyState, verifyTransfer, exportEvidence as exportPolicyEvidence, summarizePolicyState, summarizePolicyOutputDescriptor, summarizePolicyTransferDescriptor, validatePolicyState, validatePolicyOutputDescriptor, validatePolicyTransferDescriptor, } from "./domain/policies";
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
export declare const LIQUID_ATOMIC_DVP_PSET_SCHEME: "rwa-liquid-atomic-dvp-pset";
|
|
2
|
+
export declare const LIQUID_ATOMIC_DVP_PSET_MODE: "service_cosign_atomic_pset_v1";
|
|
3
|
+
export type LiquidAtomicDvpNetwork = "liquidtestnet" | "liquidv1";
|
|
4
|
+
export interface LiquidAtomicDvpOutputRequirement {
|
|
5
|
+
assetId: string;
|
|
6
|
+
amountAtomic: string;
|
|
7
|
+
recipient: string;
|
|
8
|
+
}
|
|
9
|
+
export interface LiquidAtomicDvpServiceSigner {
|
|
10
|
+
type: "operator_wallet" | "simplicity";
|
|
11
|
+
xonly?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface LiquidAtomicDvpRequirementsInput {
|
|
14
|
+
network?: LiquidAtomicDvpNetwork;
|
|
15
|
+
paymentRequestId: string;
|
|
16
|
+
resource: string;
|
|
17
|
+
termsHash: string;
|
|
18
|
+
policyHash?: string | null;
|
|
19
|
+
expiresAt: string | Date;
|
|
20
|
+
maxTimeoutSeconds?: number;
|
|
21
|
+
description?: string;
|
|
22
|
+
mimeType?: string;
|
|
23
|
+
payment: {
|
|
24
|
+
assetId: string;
|
|
25
|
+
amountAtomic: string | number | bigint;
|
|
26
|
+
recipient: string;
|
|
27
|
+
};
|
|
28
|
+
delivery: {
|
|
29
|
+
assetId: string;
|
|
30
|
+
amountAtomic: string | number | bigint;
|
|
31
|
+
recipient: string;
|
|
32
|
+
};
|
|
33
|
+
maxFeeSat?: string | number | bigint;
|
|
34
|
+
serviceSigner?: LiquidAtomicDvpServiceSigner | null;
|
|
35
|
+
}
|
|
36
|
+
export interface LiquidAtomicDvpRequirements {
|
|
37
|
+
scheme: typeof LIQUID_ATOMIC_DVP_PSET_SCHEME;
|
|
38
|
+
mode: typeof LIQUID_ATOMIC_DVP_PSET_MODE;
|
|
39
|
+
network: LiquidAtomicDvpNetwork;
|
|
40
|
+
paymentRequestId: string;
|
|
41
|
+
resource: string;
|
|
42
|
+
description: string;
|
|
43
|
+
mimeType: string;
|
|
44
|
+
expiresAt: string;
|
|
45
|
+
maxTimeoutSeconds: number;
|
|
46
|
+
termsHash: string;
|
|
47
|
+
policyHash: string | null;
|
|
48
|
+
summaryHash: string;
|
|
49
|
+
maxFeeSat: string | null;
|
|
50
|
+
outputs: {
|
|
51
|
+
paymentToTreasury: LiquidAtomicDvpOutputRequirement;
|
|
52
|
+
rwaToBuyer: LiquidAtomicDvpOutputRequirement;
|
|
53
|
+
};
|
|
54
|
+
serviceSigner: LiquidAtomicDvpServiceSigner | null;
|
|
55
|
+
extra: {
|
|
56
|
+
settlementMode: typeof LIQUID_ATOMIC_DVP_PSET_MODE;
|
|
57
|
+
payment: LiquidAtomicDvpOutputRequirement;
|
|
58
|
+
delivery: LiquidAtomicDvpOutputRequirement;
|
|
59
|
+
feeAsset: "lbtc";
|
|
60
|
+
maxFeeSat: string | null;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface LiquidAtomicDvpPaymentPayload {
|
|
64
|
+
scheme: typeof LIQUID_ATOMIC_DVP_PSET_SCHEME;
|
|
65
|
+
mode?: typeof LIQUID_ATOMIC_DVP_PSET_MODE;
|
|
66
|
+
network: LiquidAtomicDvpNetwork;
|
|
67
|
+
paymentRequestId: string;
|
|
68
|
+
psetBase64: string;
|
|
69
|
+
summaryHash: string;
|
|
70
|
+
expiresAt?: string;
|
|
71
|
+
payer?: string;
|
|
72
|
+
metadata?: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
export interface LiquidAtomicDvpLwkWasmModule {
|
|
75
|
+
Address: {
|
|
76
|
+
new (value: string): any;
|
|
77
|
+
parse?: (value: string, network: any) => any;
|
|
78
|
+
};
|
|
79
|
+
AssetId: {
|
|
80
|
+
new (value: string): any;
|
|
81
|
+
fromString?: (value: string) => any;
|
|
82
|
+
};
|
|
83
|
+
EsploraClient: new (network: any, url: string, waterfalls: boolean, concurrency: number, utxoOnly: boolean) => any;
|
|
84
|
+
Mnemonic: new (value: string) => any;
|
|
85
|
+
Network: {
|
|
86
|
+
mainnet: () => any;
|
|
87
|
+
testnet: () => any;
|
|
88
|
+
};
|
|
89
|
+
OutPoint: {
|
|
90
|
+
new (value: string): any;
|
|
91
|
+
};
|
|
92
|
+
Pset: {
|
|
93
|
+
new (value: string): any;
|
|
94
|
+
};
|
|
95
|
+
Signer: new (mnemonic: any, network: any) => any;
|
|
96
|
+
Transaction?: {
|
|
97
|
+
new (value: string): any;
|
|
98
|
+
fromString?: (value: string) => any;
|
|
99
|
+
};
|
|
100
|
+
UnvalidatedLiquidexProposal: {
|
|
101
|
+
fromPset: (pset: any) => any;
|
|
102
|
+
new?: (value: string) => any;
|
|
103
|
+
};
|
|
104
|
+
Wollet: new (network: any, descriptor: any) => any;
|
|
105
|
+
}
|
|
106
|
+
export interface LiquidAtomicDvpPrepareMakerProposalInput {
|
|
107
|
+
requirements: LiquidAtomicDvpRequirements | Record<string, unknown>;
|
|
108
|
+
mnemonic: string;
|
|
109
|
+
deliveryOutpoint?: string;
|
|
110
|
+
esploraUrl?: string;
|
|
111
|
+
waterfalls?: boolean;
|
|
112
|
+
concurrency?: number;
|
|
113
|
+
utxoOnly?: boolean;
|
|
114
|
+
scan?: boolean;
|
|
115
|
+
scanToIndex?: number;
|
|
116
|
+
feeRate?: number;
|
|
117
|
+
sign?: boolean;
|
|
118
|
+
lwk?: LiquidAtomicDvpLwkWasmModule;
|
|
119
|
+
importLwk?: () => Promise<LiquidAtomicDvpLwkWasmModule>;
|
|
120
|
+
}
|
|
121
|
+
export interface LiquidAtomicDvpPrepareMakerProposalResult {
|
|
122
|
+
proposalPsetBase64: string;
|
|
123
|
+
proposal: string;
|
|
124
|
+
deliveryOutpoint: string;
|
|
125
|
+
deliveryAssetId: string;
|
|
126
|
+
deliveryAmountAtomic: string;
|
|
127
|
+
paymentAssetId: string;
|
|
128
|
+
paymentAmountAtomic: string;
|
|
129
|
+
paymentRecipient: string;
|
|
130
|
+
summaryHash: string;
|
|
131
|
+
descriptor: string;
|
|
132
|
+
dwid?: string;
|
|
133
|
+
}
|
|
134
|
+
export interface LiquidAtomicDvpTakeProposalInput {
|
|
135
|
+
requirements: LiquidAtomicDvpRequirements | Record<string, unknown>;
|
|
136
|
+
mnemonic: string;
|
|
137
|
+
proposal?: string;
|
|
138
|
+
proposalPsetBase64?: string;
|
|
139
|
+
proposalTxHex?: string;
|
|
140
|
+
payer?: string;
|
|
141
|
+
esploraUrl?: string;
|
|
142
|
+
waterfalls?: boolean;
|
|
143
|
+
concurrency?: number;
|
|
144
|
+
utxoOnly?: boolean;
|
|
145
|
+
scan?: boolean;
|
|
146
|
+
scanToIndex?: number;
|
|
147
|
+
feeRate?: number;
|
|
148
|
+
finalize?: boolean;
|
|
149
|
+
lwk?: LiquidAtomicDvpLwkWasmModule;
|
|
150
|
+
importLwk?: () => Promise<LiquidAtomicDvpLwkWasmModule>;
|
|
151
|
+
}
|
|
152
|
+
export type LiquidAtomicDvpTakeProposalResult = ReturnType<typeof buildLiquidAtomicDvpPaymentFromPset> & {
|
|
153
|
+
descriptor: string;
|
|
154
|
+
dwid?: string;
|
|
155
|
+
proposalInput: LiquidAtomicDvpOutputRequirement;
|
|
156
|
+
proposalOutput: LiquidAtomicDvpOutputRequirement;
|
|
157
|
+
};
|
|
158
|
+
export interface LiquidAtomicDvpVerifyPayloadResult {
|
|
159
|
+
isValid: boolean;
|
|
160
|
+
invalidReason?: string;
|
|
161
|
+
network?: LiquidAtomicDvpNetwork;
|
|
162
|
+
paymentRequestId?: string;
|
|
163
|
+
summaryHash?: string;
|
|
164
|
+
}
|
|
165
|
+
export declare function buildLiquidAtomicDvpRequirements(input: LiquidAtomicDvpRequirementsInput): LiquidAtomicDvpRequirements;
|
|
166
|
+
export declare function prepareLiquidAtomicDvpLwkWasmMakerProposal(input: LiquidAtomicDvpPrepareMakerProposalInput): Promise<LiquidAtomicDvpPrepareMakerProposalResult>;
|
|
167
|
+
export declare function prepareLiquidAtomicDvpLwkWasmTakerPayment(input: LiquidAtomicDvpTakeProposalInput): Promise<LiquidAtomicDvpTakeProposalResult>;
|
|
168
|
+
export declare function buildLiquidAtomicDvpSummaryHash(input: {
|
|
169
|
+
network: LiquidAtomicDvpNetwork;
|
|
170
|
+
paymentRequestId: string;
|
|
171
|
+
termsHash: string;
|
|
172
|
+
policyHash: string | null;
|
|
173
|
+
expiresAt: string;
|
|
174
|
+
maxFeeSat: string | null;
|
|
175
|
+
payment: LiquidAtomicDvpOutputRequirement;
|
|
176
|
+
delivery: LiquidAtomicDvpOutputRequirement;
|
|
177
|
+
serviceSigner: LiquidAtomicDvpServiceSigner | null;
|
|
178
|
+
}): string;
|
|
179
|
+
export declare function encodeLiquidAtomicDvpPayment(payload: LiquidAtomicDvpPaymentPayload): string;
|
|
180
|
+
export declare function decodeLiquidAtomicDvpPayment(raw: string): LiquidAtomicDvpPaymentPayload | null;
|
|
181
|
+
export declare function buildLiquidAtomicDvpPaymentFromPset(input: {
|
|
182
|
+
requirements: LiquidAtomicDvpRequirements | Record<string, unknown>;
|
|
183
|
+
psetBase64: string;
|
|
184
|
+
payer?: string;
|
|
185
|
+
metadata?: Record<string, unknown>;
|
|
186
|
+
}): {
|
|
187
|
+
paymentPayload: LiquidAtomicDvpPaymentPayload;
|
|
188
|
+
xPayment: string;
|
|
189
|
+
psetBase64: string;
|
|
190
|
+
summaryHash: string;
|
|
191
|
+
};
|
|
192
|
+
export declare function verifyLiquidAtomicDvpPayment(input: {
|
|
193
|
+
requirements: LiquidAtomicDvpRequirements | Record<string, unknown>;
|
|
194
|
+
paymentPayload: LiquidAtomicDvpPaymentPayload | Record<string, unknown>;
|
|
195
|
+
now?: Date;
|
|
196
|
+
}): LiquidAtomicDvpVerifyPayloadResult;
|
|
197
|
+
export declare function coerceAtomicRequirements(value: LiquidAtomicDvpRequirements | Record<string, unknown>): LiquidAtomicDvpRequirements;
|
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LIQUID_ATOMIC_DVP_PSET_MODE = exports.LIQUID_ATOMIC_DVP_PSET_SCHEME = void 0;
|
|
4
|
+
exports.buildLiquidAtomicDvpRequirements = buildLiquidAtomicDvpRequirements;
|
|
5
|
+
exports.prepareLiquidAtomicDvpLwkWasmMakerProposal = prepareLiquidAtomicDvpLwkWasmMakerProposal;
|
|
6
|
+
exports.prepareLiquidAtomicDvpLwkWasmTakerPayment = prepareLiquidAtomicDvpLwkWasmTakerPayment;
|
|
7
|
+
exports.buildLiquidAtomicDvpSummaryHash = buildLiquidAtomicDvpSummaryHash;
|
|
8
|
+
exports.encodeLiquidAtomicDvpPayment = encodeLiquidAtomicDvpPayment;
|
|
9
|
+
exports.decodeLiquidAtomicDvpPayment = decodeLiquidAtomicDvpPayment;
|
|
10
|
+
exports.buildLiquidAtomicDvpPaymentFromPset = buildLiquidAtomicDvpPaymentFromPset;
|
|
11
|
+
exports.verifyLiquidAtomicDvpPayment = verifyLiquidAtomicDvpPayment;
|
|
12
|
+
exports.coerceAtomicRequirements = coerceAtomicRequirements;
|
|
13
|
+
const node_crypto_1 = require("node:crypto");
|
|
14
|
+
const summary_1 = require("../core/summary");
|
|
15
|
+
exports.LIQUID_ATOMIC_DVP_PSET_SCHEME = "rwa-liquid-atomic-dvp-pset";
|
|
16
|
+
exports.LIQUID_ATOMIC_DVP_PSET_MODE = "service_cosign_atomic_pset_v1";
|
|
17
|
+
;
|
|
18
|
+
function buildLiquidAtomicDvpRequirements(input) {
|
|
19
|
+
const network = normalizeAtomicNetwork(input.network ?? "liquidtestnet");
|
|
20
|
+
const paymentRequestId = requiredString(input.paymentRequestId, "paymentRequestId");
|
|
21
|
+
const resource = requiredString(input.resource, "resource");
|
|
22
|
+
const termsHash = requiredString(input.termsHash, "termsHash");
|
|
23
|
+
const policyHash = input.policyHash ?? null;
|
|
24
|
+
const expiresAt = normalizeDateTime(input.expiresAt, "expiresAt");
|
|
25
|
+
const maxTimeoutSeconds = normalizeTimeout(input.maxTimeoutSeconds);
|
|
26
|
+
const payment = normalizeOutput(input.payment, "payment");
|
|
27
|
+
const delivery = normalizeOutput(input.delivery, "delivery");
|
|
28
|
+
const maxFeeSat = input.maxFeeSat === undefined ? null : normalizeInteger(input.maxFeeSat, "maxFeeSat");
|
|
29
|
+
const serviceSigner = normalizeServiceSigner(input.serviceSigner);
|
|
30
|
+
const summaryHash = buildLiquidAtomicDvpSummaryHash({
|
|
31
|
+
network,
|
|
32
|
+
paymentRequestId,
|
|
33
|
+
termsHash,
|
|
34
|
+
policyHash,
|
|
35
|
+
expiresAt,
|
|
36
|
+
maxFeeSat,
|
|
37
|
+
payment,
|
|
38
|
+
delivery,
|
|
39
|
+
serviceSigner,
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
scheme: exports.LIQUID_ATOMIC_DVP_PSET_SCHEME,
|
|
43
|
+
mode: exports.LIQUID_ATOMIC_DVP_PSET_MODE,
|
|
44
|
+
network,
|
|
45
|
+
paymentRequestId,
|
|
46
|
+
resource,
|
|
47
|
+
description: String(input.description ?? "").trim() || "Hazbase RWA atomic Liquid DvP payment",
|
|
48
|
+
mimeType: String(input.mimeType ?? "").trim() || "application/json",
|
|
49
|
+
expiresAt,
|
|
50
|
+
maxTimeoutSeconds,
|
|
51
|
+
termsHash,
|
|
52
|
+
policyHash,
|
|
53
|
+
summaryHash,
|
|
54
|
+
maxFeeSat,
|
|
55
|
+
outputs: {
|
|
56
|
+
paymentToTreasury: payment,
|
|
57
|
+
rwaToBuyer: delivery,
|
|
58
|
+
},
|
|
59
|
+
serviceSigner,
|
|
60
|
+
extra: {
|
|
61
|
+
settlementMode: exports.LIQUID_ATOMIC_DVP_PSET_MODE,
|
|
62
|
+
payment,
|
|
63
|
+
delivery,
|
|
64
|
+
feeAsset: "lbtc",
|
|
65
|
+
maxFeeSat,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function prepareLiquidAtomicDvpLwkWasmMakerProposal(input) {
|
|
70
|
+
const requirements = coerceAtomicRequirements(input.requirements);
|
|
71
|
+
ensureLwkWasmNodeTimerCompat();
|
|
72
|
+
const lwk = input.lwk ?? await loadLwkWasm(input.importLwk);
|
|
73
|
+
const { network, signer, descriptor, wollet } = await buildLwkContext(lwk, requirements.network, input.mnemonic, input);
|
|
74
|
+
const delivery = requirements.outputs.rwaToBuyer;
|
|
75
|
+
const payment = requirements.outputs.paymentToTreasury;
|
|
76
|
+
const deliveryUtxo = selectExactDeliveryUtxo(wollet, delivery, input.deliveryOutpoint);
|
|
77
|
+
const paymentRecipient = parseLwkAddress(lwk, payment.recipient, network);
|
|
78
|
+
let builder = network.txBuilder();
|
|
79
|
+
if (input.feeRate !== undefined)
|
|
80
|
+
builder = builder.feeRate(input.feeRate);
|
|
81
|
+
builder = builder.liquidexMake(deliveryUtxo.outpoint, paymentRecipient, BigInt(payment.amountAtomic), parseLwkAssetId(lwk, payment.assetId));
|
|
82
|
+
const unsigned = builder.finish(wollet);
|
|
83
|
+
const proposalPset = input.sign === false ? unsigned : signer.sign(unsigned);
|
|
84
|
+
const proposalPsetBase64 = proposalPset.toString();
|
|
85
|
+
const proposal = lwk.UnvalidatedLiquidexProposal.fromPset(proposalPset).toString();
|
|
86
|
+
return {
|
|
87
|
+
proposalPsetBase64,
|
|
88
|
+
proposal,
|
|
89
|
+
deliveryOutpoint: deliveryUtxo.outpointText,
|
|
90
|
+
deliveryAssetId: delivery.assetId,
|
|
91
|
+
deliveryAmountAtomic: delivery.amountAtomic,
|
|
92
|
+
paymentAssetId: payment.assetId,
|
|
93
|
+
paymentAmountAtomic: payment.amountAtomic,
|
|
94
|
+
paymentRecipient: payment.recipient,
|
|
95
|
+
summaryHash: requirements.summaryHash,
|
|
96
|
+
descriptor: descriptor.toString(),
|
|
97
|
+
...(typeof wollet.dwid === "function" ? { dwid: wollet.dwid() } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function prepareLiquidAtomicDvpLwkWasmTakerPayment(input) {
|
|
101
|
+
const requirements = coerceAtomicRequirements(input.requirements);
|
|
102
|
+
ensureLwkWasmNodeTimerCompat();
|
|
103
|
+
const lwk = input.lwk ?? await loadLwkWasm(input.importLwk);
|
|
104
|
+
const { network, signer, descriptor, wollet } = await buildLwkContext(lwk, requirements.network, input.mnemonic, input);
|
|
105
|
+
const proposal = parseLiquidexProposal(lwk, input.proposalPsetBase64 ?? input.proposal);
|
|
106
|
+
const validated = input.proposalTxHex
|
|
107
|
+
? proposal.validate(parseLwkTransaction(lwk, input.proposalTxHex))
|
|
108
|
+
: proposal.insecureValidate();
|
|
109
|
+
const proposalInput = assetAmountRequirement(validated.input());
|
|
110
|
+
const proposalOutput = assetAmountRequirement(validated.output());
|
|
111
|
+
assertOutputMatches(proposalInput, requirements.outputs.rwaToBuyer, "Liquidex maker input");
|
|
112
|
+
assertOutputMatches(proposalOutput, requirements.outputs.paymentToTreasury, "Liquidex maker output");
|
|
113
|
+
let builder = network.txBuilder();
|
|
114
|
+
if (input.feeRate !== undefined)
|
|
115
|
+
builder = builder.feeRate(input.feeRate);
|
|
116
|
+
builder = builder.liquidexTake([validated]);
|
|
117
|
+
const unsigned = builder.finish(wollet);
|
|
118
|
+
const signed = signer.sign(unsigned);
|
|
119
|
+
const pset = input.finalize === false ? signed : wollet.finalize(signed);
|
|
120
|
+
const payment = buildLiquidAtomicDvpPaymentFromPset({
|
|
121
|
+
requirements,
|
|
122
|
+
psetBase64: pset.toString(),
|
|
123
|
+
payer: input.payer,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
...payment,
|
|
127
|
+
descriptor: descriptor.toString(),
|
|
128
|
+
...(typeof wollet.dwid === "function" ? { dwid: wollet.dwid() } : {}),
|
|
129
|
+
proposalInput,
|
|
130
|
+
proposalOutput,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function buildLiquidAtomicDvpSummaryHash(input) {
|
|
134
|
+
return sha256Hex((0, summary_1.stableStringify)({
|
|
135
|
+
scheme: exports.LIQUID_ATOMIC_DVP_PSET_SCHEME,
|
|
136
|
+
mode: exports.LIQUID_ATOMIC_DVP_PSET_MODE,
|
|
137
|
+
network: input.network,
|
|
138
|
+
paymentRequestId: input.paymentRequestId,
|
|
139
|
+
termsHash: input.termsHash,
|
|
140
|
+
policyHash: input.policyHash,
|
|
141
|
+
expiresAt: input.expiresAt,
|
|
142
|
+
maxFeeSat: input.maxFeeSat,
|
|
143
|
+
outputs: {
|
|
144
|
+
paymentToTreasury: input.payment,
|
|
145
|
+
rwaToBuyer: input.delivery,
|
|
146
|
+
},
|
|
147
|
+
serviceSigner: input.serviceSigner
|
|
148
|
+
? {
|
|
149
|
+
type: input.serviceSigner.type,
|
|
150
|
+
xonly: input.serviceSigner.xonly ?? null,
|
|
151
|
+
}
|
|
152
|
+
: null,
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
function encodeLiquidAtomicDvpPayment(payload) {
|
|
156
|
+
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
157
|
+
}
|
|
158
|
+
function decodeLiquidAtomicDvpPayment(raw) {
|
|
159
|
+
const value = String(raw ?? "").trim();
|
|
160
|
+
if (!value)
|
|
161
|
+
return null;
|
|
162
|
+
try {
|
|
163
|
+
const parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
164
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
165
|
+
return null;
|
|
166
|
+
if (String(parsed.scheme ?? "") !== exports.LIQUID_ATOMIC_DVP_PSET_SCHEME)
|
|
167
|
+
return null;
|
|
168
|
+
return coerceAtomicPayload(parsed);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function buildLiquidAtomicDvpPaymentFromPset(input) {
|
|
175
|
+
const requirements = coerceAtomicRequirements(input.requirements);
|
|
176
|
+
const psetBase64 = requiredString(input.psetBase64, "psetBase64");
|
|
177
|
+
const paymentPayload = {
|
|
178
|
+
scheme: exports.LIQUID_ATOMIC_DVP_PSET_SCHEME,
|
|
179
|
+
mode: exports.LIQUID_ATOMIC_DVP_PSET_MODE,
|
|
180
|
+
network: requirements.network,
|
|
181
|
+
paymentRequestId: requirements.paymentRequestId,
|
|
182
|
+
psetBase64,
|
|
183
|
+
summaryHash: requirements.summaryHash,
|
|
184
|
+
expiresAt: requirements.expiresAt,
|
|
185
|
+
...(input.payer ? { payer: input.payer } : {}),
|
|
186
|
+
...(input.metadata ? { metadata: input.metadata } : {}),
|
|
187
|
+
};
|
|
188
|
+
return {
|
|
189
|
+
paymentPayload,
|
|
190
|
+
xPayment: encodeLiquidAtomicDvpPayment(paymentPayload),
|
|
191
|
+
psetBase64,
|
|
192
|
+
summaryHash: requirements.summaryHash,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function verifyLiquidAtomicDvpPayment(input) {
|
|
196
|
+
const requirements = coerceAtomicRequirements(input.requirements);
|
|
197
|
+
const payload = coerceAtomicPayload(input.paymentPayload);
|
|
198
|
+
const now = input.now ?? new Date();
|
|
199
|
+
const base = {
|
|
200
|
+
network: payload.network,
|
|
201
|
+
paymentRequestId: payload.paymentRequestId,
|
|
202
|
+
summaryHash: payload.summaryHash,
|
|
203
|
+
};
|
|
204
|
+
if (payload.scheme !== exports.LIQUID_ATOMIC_DVP_PSET_SCHEME) {
|
|
205
|
+
return { ...base, isValid: false, invalidReason: "scheme_mismatch" };
|
|
206
|
+
}
|
|
207
|
+
if (payload.network !== requirements.network)
|
|
208
|
+
return { ...base, isValid: false, invalidReason: "network_mismatch" };
|
|
209
|
+
if (payload.paymentRequestId !== requirements.paymentRequestId) {
|
|
210
|
+
return { ...base, isValid: false, invalidReason: "payment_request_id_mismatch" };
|
|
211
|
+
}
|
|
212
|
+
if (normalizeHexHash(payload.summaryHash) !== normalizeHexHash(requirements.summaryHash)) {
|
|
213
|
+
return { ...base, isValid: false, invalidReason: "summary_hash_mismatch" };
|
|
214
|
+
}
|
|
215
|
+
if (!payload.psetBase64)
|
|
216
|
+
return { ...base, isValid: false, invalidReason: "pset_missing" };
|
|
217
|
+
if (!looksBase64(payload.psetBase64))
|
|
218
|
+
return { ...base, isValid: false, invalidReason: "pset_invalid_base64" };
|
|
219
|
+
if (new Date(payload.expiresAt ?? requirements.expiresAt).getTime() <= now.getTime()) {
|
|
220
|
+
return { ...base, isValid: false, invalidReason: "payment_expired" };
|
|
221
|
+
}
|
|
222
|
+
return { ...base, isValid: true };
|
|
223
|
+
}
|
|
224
|
+
function coerceAtomicRequirements(value) {
|
|
225
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
226
|
+
throw new Error("atomic DvP requirements must be an object");
|
|
227
|
+
}
|
|
228
|
+
const raw = value;
|
|
229
|
+
const outputs = raw.outputs && typeof raw.outputs === "object" && !Array.isArray(raw.outputs) ? raw.outputs : {};
|
|
230
|
+
const extra = raw.extra && typeof raw.extra === "object" && !Array.isArray(raw.extra) ? raw.extra : {};
|
|
231
|
+
const payment = normalizeOutput(outputs.paymentToTreasury ?? extra.payment, "paymentToTreasury");
|
|
232
|
+
const delivery = normalizeOutput(outputs.rwaToBuyer ?? extra.delivery, "rwaToBuyer");
|
|
233
|
+
const network = normalizeAtomicNetwork(raw.network);
|
|
234
|
+
const policyHash = typeof raw.policyHash === "string" && raw.policyHash.trim() ? raw.policyHash.trim() : null;
|
|
235
|
+
const maxFeeSat = raw.maxFeeSat === null || raw.maxFeeSat === undefined ? null : normalizeInteger(raw.maxFeeSat, "maxFeeSat");
|
|
236
|
+
const serviceSigner = normalizeServiceSigner(raw.serviceSigner);
|
|
237
|
+
const fallbackSummaryHash = buildLiquidAtomicDvpSummaryHash({
|
|
238
|
+
network,
|
|
239
|
+
paymentRequestId: requiredString(raw.paymentRequestId, "paymentRequestId"),
|
|
240
|
+
termsHash: requiredString(raw.termsHash, "termsHash"),
|
|
241
|
+
policyHash,
|
|
242
|
+
expiresAt: normalizeDateTime(raw.expiresAt, "expiresAt"),
|
|
243
|
+
maxFeeSat,
|
|
244
|
+
payment,
|
|
245
|
+
delivery,
|
|
246
|
+
serviceSigner,
|
|
247
|
+
});
|
|
248
|
+
return {
|
|
249
|
+
scheme: exports.LIQUID_ATOMIC_DVP_PSET_SCHEME,
|
|
250
|
+
mode: exports.LIQUID_ATOMIC_DVP_PSET_MODE,
|
|
251
|
+
network,
|
|
252
|
+
paymentRequestId: requiredString(raw.paymentRequestId, "paymentRequestId"),
|
|
253
|
+
resource: requiredString(raw.resource, "resource"),
|
|
254
|
+
description: String(raw.description ?? "").trim() || "Hazbase RWA atomic Liquid DvP payment",
|
|
255
|
+
mimeType: String(raw.mimeType ?? "").trim() || "application/json",
|
|
256
|
+
expiresAt: normalizeDateTime(raw.expiresAt, "expiresAt"),
|
|
257
|
+
maxTimeoutSeconds: normalizeTimeout(raw.maxTimeoutSeconds),
|
|
258
|
+
termsHash: requiredString(raw.termsHash, "termsHash"),
|
|
259
|
+
policyHash,
|
|
260
|
+
summaryHash: typeof raw.summaryHash === "string" && raw.summaryHash.trim() ? raw.summaryHash.trim() : fallbackSummaryHash,
|
|
261
|
+
maxFeeSat,
|
|
262
|
+
outputs: {
|
|
263
|
+
paymentToTreasury: payment,
|
|
264
|
+
rwaToBuyer: delivery,
|
|
265
|
+
},
|
|
266
|
+
serviceSigner,
|
|
267
|
+
extra: {
|
|
268
|
+
settlementMode: exports.LIQUID_ATOMIC_DVP_PSET_MODE,
|
|
269
|
+
payment,
|
|
270
|
+
delivery,
|
|
271
|
+
feeAsset: "lbtc",
|
|
272
|
+
maxFeeSat,
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function coerceAtomicPayload(value) {
|
|
277
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
278
|
+
throw new Error("atomic DvP payment payload must be an object");
|
|
279
|
+
}
|
|
280
|
+
const raw = value;
|
|
281
|
+
return {
|
|
282
|
+
scheme: String(raw.scheme ?? exports.LIQUID_ATOMIC_DVP_PSET_SCHEME),
|
|
283
|
+
mode: raw.mode === exports.LIQUID_ATOMIC_DVP_PSET_MODE ? exports.LIQUID_ATOMIC_DVP_PSET_MODE : undefined,
|
|
284
|
+
network: normalizeAtomicNetwork(raw.network),
|
|
285
|
+
paymentRequestId: requiredString(raw.paymentRequestId, "paymentRequestId"),
|
|
286
|
+
psetBase64: requiredString(raw.psetBase64, "psetBase64"),
|
|
287
|
+
summaryHash: requiredString(raw.summaryHash, "summaryHash"),
|
|
288
|
+
expiresAt: typeof raw.expiresAt === "string" ? raw.expiresAt : undefined,
|
|
289
|
+
...(typeof raw.payer === "string" && raw.payer.trim() ? { payer: raw.payer.trim() } : {}),
|
|
290
|
+
...(raw.metadata && typeof raw.metadata === "object" && !Array.isArray(raw.metadata)
|
|
291
|
+
? { metadata: raw.metadata }
|
|
292
|
+
: {}),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
async function loadLwkWasm(importer) {
|
|
296
|
+
ensureLwkWasmNodeTimerCompat();
|
|
297
|
+
if (importer)
|
|
298
|
+
return importer();
|
|
299
|
+
const dynamicImport = new Function("specifier", "return import(specifier)");
|
|
300
|
+
const failures = [];
|
|
301
|
+
for (const specifier of ["lwk_wasm", "lwk_node"]) {
|
|
302
|
+
try {
|
|
303
|
+
const imported = await dynamicImport(specifier);
|
|
304
|
+
return imported.default ?? imported;
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
failures.push(`${specifier}: ${error instanceof Error ? error.message : String(error)}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
throw new Error("lwk_wasm or lwk_node is required for atomic Liquid DvP PSETs. " +
|
|
311
|
+
`Import failed: ${failures.join("; ")}`);
|
|
312
|
+
}
|
|
313
|
+
function ensureLwkWasmNodeTimerCompat() {
|
|
314
|
+
const scope = globalThis;
|
|
315
|
+
if (typeof scope.window === "undefined" && typeof scope.setTimeout === "function") {
|
|
316
|
+
scope.window = scope;
|
|
317
|
+
}
|
|
318
|
+
if (typeof scope.Window === "undefined" && typeof scope.window !== "undefined") {
|
|
319
|
+
scope.Window = Object;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async function buildLwkContext(lwk, networkKey, mnemonicText, options) {
|
|
323
|
+
const network = networkKey === "liquidv1" ? lwk.Network.mainnet() : lwk.Network.testnet();
|
|
324
|
+
const mnemonic = new lwk.Mnemonic(mnemonicText);
|
|
325
|
+
const signer = new lwk.Signer(mnemonic, network);
|
|
326
|
+
const descriptor = signer.wpkhSlip77Descriptor();
|
|
327
|
+
const wollet = new lwk.Wollet(network, descriptor);
|
|
328
|
+
if (options.scan !== false) {
|
|
329
|
+
const client = options.esploraUrl
|
|
330
|
+
? new lwk.EsploraClient(network, options.esploraUrl, options.waterfalls ?? false, options.concurrency ?? 4, options.utxoOnly ?? false)
|
|
331
|
+
: network.defaultEsploraClient();
|
|
332
|
+
const update = options.scanToIndex !== undefined
|
|
333
|
+
? await client.fullScanToIndex(wollet, options.scanToIndex)
|
|
334
|
+
: await client.fullScan(wollet);
|
|
335
|
+
if (update)
|
|
336
|
+
wollet.applyUpdate(update);
|
|
337
|
+
}
|
|
338
|
+
return { network, signer, descriptor, wollet };
|
|
339
|
+
}
|
|
340
|
+
function parseLwkAddress(lwk, address, network) {
|
|
341
|
+
if (typeof lwk.Address.parse === "function") {
|
|
342
|
+
try {
|
|
343
|
+
return lwk.Address.parse(address, network);
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
347
|
+
if (!message.includes("non-blinded"))
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return new lwk.Address(address);
|
|
352
|
+
}
|
|
353
|
+
function parseLwkAssetId(lwk, assetId) {
|
|
354
|
+
return typeof lwk.AssetId.fromString === "function" ? lwk.AssetId.fromString(assetId) : new lwk.AssetId(assetId);
|
|
355
|
+
}
|
|
356
|
+
function parseLwkTransaction(lwk, txHex) {
|
|
357
|
+
if (lwk.Transaction?.fromString)
|
|
358
|
+
return lwk.Transaction.fromString(txHex);
|
|
359
|
+
if (lwk.Transaction)
|
|
360
|
+
return new lwk.Transaction(txHex);
|
|
361
|
+
throw new Error("LWK Transaction support is required to validate a Liquidex proposal against a transaction.");
|
|
362
|
+
}
|
|
363
|
+
function parseLiquidexProposal(lwk, value) {
|
|
364
|
+
const encoded = String(value ?? "").trim();
|
|
365
|
+
if (!encoded)
|
|
366
|
+
throw new Error("Liquidex proposal PSET is required");
|
|
367
|
+
try {
|
|
368
|
+
return lwk.UnvalidatedLiquidexProposal.fromPset(new lwk.Pset(encoded));
|
|
369
|
+
}
|
|
370
|
+
catch (psetError) {
|
|
371
|
+
if (typeof lwk.UnvalidatedLiquidexProposal.new === "function") {
|
|
372
|
+
try {
|
|
373
|
+
return lwk.UnvalidatedLiquidexProposal.new(encoded);
|
|
374
|
+
}
|
|
375
|
+
catch { }
|
|
376
|
+
}
|
|
377
|
+
throw psetError;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function selectExactDeliveryUtxo(wollet, delivery, requestedOutpoint) {
|
|
381
|
+
const utxos = typeof wollet.utxos === "function" ? wollet.utxos() : [];
|
|
382
|
+
for (const utxo of utxos) {
|
|
383
|
+
const outpoint = utxo.outpoint();
|
|
384
|
+
const outpointText = outpointString(outpoint);
|
|
385
|
+
if (requestedOutpoint && outpointText !== requestedOutpoint)
|
|
386
|
+
continue;
|
|
387
|
+
const secrets = utxo.unblinded();
|
|
388
|
+
const assetId = secrets?.asset?.().toString?.();
|
|
389
|
+
const amountAtomic = secrets?.value?.().toString?.();
|
|
390
|
+
if (assetId === delivery.assetId && amountAtomic === delivery.amountAtomic) {
|
|
391
|
+
return { outpoint, outpointText };
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (requestedOutpoint) {
|
|
395
|
+
throw new Error(`Delivery UTXO ${requestedOutpoint} is not an exact match for the atomic DvP delivery output.`);
|
|
396
|
+
}
|
|
397
|
+
throw new Error("No exact Liquid RWA UTXO is available for the atomic DvP delivery output.");
|
|
398
|
+
}
|
|
399
|
+
function outpointString(outpoint) {
|
|
400
|
+
try {
|
|
401
|
+
return `${outpoint.txid().toString()}:${outpoint.vout()}`;
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
return String(outpoint);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function assetAmountRequirement(value) {
|
|
408
|
+
return {
|
|
409
|
+
assetId: value.asset().toString(),
|
|
410
|
+
amountAtomic: value.amount().toString(),
|
|
411
|
+
recipient: "",
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function assertOutputMatches(actual, expected, label) {
|
|
415
|
+
if (actual.assetId !== expected.assetId || actual.amountAtomic !== expected.amountAtomic) {
|
|
416
|
+
throw new Error(`${label} does not match atomic DvP requirements: ` +
|
|
417
|
+
`expected ${expected.amountAtomic} ${expected.assetId}, got ${actual.amountAtomic} ${actual.assetId}`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function normalizeAtomicNetwork(value) {
|
|
421
|
+
if (value === "liquidv1")
|
|
422
|
+
return "liquidv1";
|
|
423
|
+
if (value === "liquidtestnet" || value === undefined || value === null || value === "")
|
|
424
|
+
return "liquidtestnet";
|
|
425
|
+
throw new Error(`unsupported Liquid atomic DvP network: ${String(value)}`);
|
|
426
|
+
}
|
|
427
|
+
function normalizeOutput(value, name) {
|
|
428
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
429
|
+
throw new Error(`${name} output requirement is required`);
|
|
430
|
+
}
|
|
431
|
+
const raw = value;
|
|
432
|
+
return {
|
|
433
|
+
assetId: requiredString(raw.assetId, `${name}.assetId`),
|
|
434
|
+
amountAtomic: normalizeInteger(raw.amountAtomic, `${name}.amountAtomic`),
|
|
435
|
+
recipient: requiredString(raw.recipient, `${name}.recipient`),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function normalizeServiceSigner(value) {
|
|
439
|
+
if (value === null || value === undefined)
|
|
440
|
+
return null;
|
|
441
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
442
|
+
return null;
|
|
443
|
+
const raw = value;
|
|
444
|
+
const type = raw.type === "simplicity" ? "simplicity" : raw.type === "operator_wallet" ? "operator_wallet" : null;
|
|
445
|
+
if (!type)
|
|
446
|
+
return null;
|
|
447
|
+
const xonly = typeof raw.xonly === "string" && raw.xonly.trim() ? raw.xonly.trim() : undefined;
|
|
448
|
+
return { type, ...(xonly ? { xonly } : {}) };
|
|
449
|
+
}
|
|
450
|
+
function normalizeInteger(value, name) {
|
|
451
|
+
const text = String(value ?? "").trim();
|
|
452
|
+
if (!/^\d+$/u.test(text))
|
|
453
|
+
throw new Error(`${name} must be a non-negative integer string`);
|
|
454
|
+
return BigInt(text).toString();
|
|
455
|
+
}
|
|
456
|
+
function normalizeDateTime(value, name) {
|
|
457
|
+
const date = value instanceof Date ? value : new Date(String(value ?? ""));
|
|
458
|
+
if (!Number.isFinite(date.getTime()))
|
|
459
|
+
throw new Error(`${name} must be a valid date`);
|
|
460
|
+
return date.toISOString();
|
|
461
|
+
}
|
|
462
|
+
function normalizeTimeout(value) {
|
|
463
|
+
const timeout = Number(value ?? 60);
|
|
464
|
+
if (!Number.isFinite(timeout) || timeout <= 0)
|
|
465
|
+
return 60;
|
|
466
|
+
return Math.floor(timeout);
|
|
467
|
+
}
|
|
468
|
+
function requiredString(value, name) {
|
|
469
|
+
const text = String(value ?? "").trim();
|
|
470
|
+
if (!text)
|
|
471
|
+
throw new Error(`${name} is required`);
|
|
472
|
+
return text;
|
|
473
|
+
}
|
|
474
|
+
function looksBase64(value) {
|
|
475
|
+
return /^[A-Za-z0-9+/]+={0,2}$/u.test(value) || /^[A-Za-z0-9_-]+={0,2}$/u.test(value);
|
|
476
|
+
}
|
|
477
|
+
function sha256Hex(value) {
|
|
478
|
+
return (0, node_crypto_1.createHash)("sha256").update(value, "utf8").digest("hex");
|
|
479
|
+
}
|
|
480
|
+
function normalizeHexHash(value) {
|
|
481
|
+
return value.trim().toLowerCase().replace(/^0x/u, "");
|
|
482
|
+
}
|
package/dist/x402/index.d.ts
CHANGED
package/dist/x402/index.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
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
18
|
exports.listLiquidX402Assets = listLiquidX402Assets;
|
|
@@ -15,6 +29,7 @@ exports.settleLiquidX402Payment = settleLiquidX402Payment;
|
|
|
15
29
|
exports.verifyLiquidX402PayloadFields = verifyLiquidX402PayloadFields;
|
|
16
30
|
exports.buildLiquidPsetSummaryHash = buildLiquidPsetSummaryHash;
|
|
17
31
|
const node_crypto_1 = require("node:crypto");
|
|
32
|
+
__exportStar(require("./atomicDvp"), exports);
|
|
18
33
|
exports.LIQUID_X402_SCHEME = "exact-liquid-pset";
|
|
19
34
|
exports.LIQUID_X402_VERSION = 1;
|
|
20
35
|
exports.LIQUID_X402_DEFAULT_NETWORK = "liquidtestnet";
|