@hazbase/simplicity 0.3.1 → 0.3.2
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/dist/x402/index.d.ts +4 -0
- package/dist/x402/index.js +62 -4
- package/package.json +1 -1
package/dist/x402/index.d.ts
CHANGED
package/dist/x402/index.js
CHANGED
|
@@ -219,6 +219,9 @@ async function prepareLiquidX402LwkWasmPayment(input) {
|
|
|
219
219
|
if (requirements.extra.asset === "lbtc") {
|
|
220
220
|
builder = builder.addLbtcRecipient(recipient, amount);
|
|
221
221
|
}
|
|
222
|
+
else if (typeof recipient.isBlinded === "function" && recipient.isBlinded() === false && typeof builder.addExplicitRecipient === "function") {
|
|
223
|
+
builder = builder.addExplicitRecipient(recipient, amount, parseLwkAssetId(lwk, requirements.asset));
|
|
224
|
+
}
|
|
222
225
|
else {
|
|
223
226
|
builder = builder.addRecipient(recipient, amount, parseLwkAssetId(lwk, requirements.asset));
|
|
224
227
|
}
|
|
@@ -270,12 +273,13 @@ async function verifyLiquidX402Payment(rpc, input) {
|
|
|
270
273
|
return basic;
|
|
271
274
|
}
|
|
272
275
|
try {
|
|
276
|
+
const expectedTarget = await resolveExpectedLiquidOutputTarget(rpc, requirements);
|
|
273
277
|
const decoded = await rpc.call("decodepsbt", [payload.psetBase64]);
|
|
274
278
|
const actualSummaryHash = buildLiquidPsetSummaryHash(decoded, requirements);
|
|
275
279
|
if (actualSummaryHash !== payload.summaryHash) {
|
|
276
280
|
return { ...basic, isValid: false, invalidReason: "pset_summary_mismatch" };
|
|
277
281
|
}
|
|
278
|
-
if (!decodedContainsExpectedOutput(decoded, requirements)) {
|
|
282
|
+
if (!decodedContainsExpectedOutput(decoded, requirements, expectedTarget)) {
|
|
279
283
|
return { ...basic, isValid: false, invalidReason: "pset_expected_output_missing" };
|
|
280
284
|
}
|
|
281
285
|
if (!decodedFeeWithinCap(decoded, requirements)) {
|
|
@@ -376,12 +380,56 @@ function buildLiquidPsetSummaryHash(_decoded, requirements) {
|
|
|
376
380
|
maxFeeSat: req.extra.maxFeeSat ?? null,
|
|
377
381
|
}));
|
|
378
382
|
}
|
|
379
|
-
function decodedContainsExpectedOutput(decoded, requirements) {
|
|
383
|
+
function decodedContainsExpectedOutput(decoded, requirements, expectedTarget = buildFallbackExpectedLiquidOutputTarget(requirements)) {
|
|
380
384
|
const expectedAmount = atomicToDecimalNumber(requirements.maxAmountRequired, requirements.extra.decimals);
|
|
381
385
|
return (decoded.outputs ?? []).some((output) => (String(output.asset ?? "").toLowerCase() === requirements.asset.toLowerCase() &&
|
|
382
386
|
Math.round(Number(output.amount ?? 0) * 10 ** requirements.extra.decimals) ===
|
|
383
387
|
Math.round(expectedAmount * 10 ** requirements.extra.decimals) &&
|
|
384
|
-
|
|
388
|
+
decodedOutputMatchesLiquidTarget(output, expectedTarget)));
|
|
389
|
+
}
|
|
390
|
+
async function resolveExpectedLiquidOutputTarget(rpc, requirements) {
|
|
391
|
+
const target = buildFallbackExpectedLiquidOutputTarget(requirements);
|
|
392
|
+
try {
|
|
393
|
+
const info = await rpc.call("validateaddress", [requirements.payTo]);
|
|
394
|
+
if (info?.isvalid !== false) {
|
|
395
|
+
addNormalizedAddress(target.addresses, info.address);
|
|
396
|
+
addNormalizedAddress(target.addresses, info.unconfidential);
|
|
397
|
+
addNormalizedAddress(target.addresses, info.confidential);
|
|
398
|
+
addNormalizedHex(target.scriptHexes, info.scriptPubKey);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
// Older or mocked RPC clients may not expose validateaddress. Exact payTo
|
|
403
|
+
// matching remains safe for unconfidential outputs in that case.
|
|
404
|
+
}
|
|
405
|
+
return target;
|
|
406
|
+
}
|
|
407
|
+
function buildFallbackExpectedLiquidOutputTarget(requirements) {
|
|
408
|
+
const target = { addresses: new Set(), scriptHexes: new Set() };
|
|
409
|
+
addNormalizedAddress(target.addresses, requirements.payTo);
|
|
410
|
+
return target;
|
|
411
|
+
}
|
|
412
|
+
function decodedOutputMatchesLiquidTarget(output, expectedTarget) {
|
|
413
|
+
const address = output.script?.address ?? output.scriptPubKey?.address;
|
|
414
|
+
const scriptHex = output.script?.hex ?? output.scriptPubKey?.hex;
|
|
415
|
+
return (expectedTarget.addresses.has(normalizeAddressForComparison(address)) ||
|
|
416
|
+
expectedTarget.scriptHexes.has(normalizeHexForComparison(scriptHex)));
|
|
417
|
+
}
|
|
418
|
+
function addNormalizedAddress(target, value) {
|
|
419
|
+
const normalized = normalizeAddressForComparison(value);
|
|
420
|
+
if (normalized)
|
|
421
|
+
target.add(normalized);
|
|
422
|
+
}
|
|
423
|
+
function addNormalizedHex(target, value) {
|
|
424
|
+
const normalized = normalizeHexForComparison(value);
|
|
425
|
+
if (normalized)
|
|
426
|
+
target.add(normalized);
|
|
427
|
+
}
|
|
428
|
+
function normalizeAddressForComparison(value) {
|
|
429
|
+
return String(value ?? "").trim().toLowerCase();
|
|
430
|
+
}
|
|
431
|
+
function normalizeHexForComparison(value) {
|
|
432
|
+
return String(value ?? "").trim().toLowerCase().replace(/^0x/u, "");
|
|
385
433
|
}
|
|
386
434
|
function coerceRequirements(value) {
|
|
387
435
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -454,7 +502,17 @@ function ensureLwkWasmNodeTimerCompat() {
|
|
|
454
502
|
}
|
|
455
503
|
}
|
|
456
504
|
function parseLwkAddress(lwk, address, network) {
|
|
457
|
-
|
|
505
|
+
if (typeof lwk.Address.parse === "function") {
|
|
506
|
+
try {
|
|
507
|
+
return lwk.Address.parse(address, network);
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
511
|
+
if (!message.includes("non-blinded"))
|
|
512
|
+
throw error;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return new lwk.Address(address);
|
|
458
516
|
}
|
|
459
517
|
function parseLwkAssetId(lwk, assetId) {
|
|
460
518
|
return typeof lwk.AssetId.fromString === "function" ? lwk.AssetId.fromString(assetId) : new lwk.AssetId(assetId);
|