@molpha/sdk 0.2.0-dev-20260911175245 → 0.2.0-dev-20260912150104
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 +67 -0
- package/dist/index.d.ts +111 -3
- package/dist/index.js +386 -4
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/{wallet-udLZ5Iy0.d.ts → wallet-B3mYmC2b.d.ts} +77 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -77,6 +77,20 @@ function assertUint(value, max, label) {
|
|
|
77
77
|
throw new RangeError(`${label} out of range: ${value}`);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
+
function bytesToBase64(bytes) {
|
|
81
|
+
let binary = "";
|
|
82
|
+
for (let i = 0; i < bytes.length; i += 32768) {
|
|
83
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
84
|
+
}
|
|
85
|
+
return btoa(binary);
|
|
86
|
+
}
|
|
87
|
+
function base64ToBytes(value) {
|
|
88
|
+
const padded = value.length % 4 === 0 ? value : value + "=".repeat(4 - value.length % 4);
|
|
89
|
+
const binary = atob(padded);
|
|
90
|
+
const out = new Uint8Array(binary.length);
|
|
91
|
+
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
80
94
|
|
|
81
95
|
// src/core/apiconfig.ts
|
|
82
96
|
function compareCodeUnits(a, b) {
|
|
@@ -308,6 +322,268 @@ function validateEncryptionRecipients(selectedNodes) {
|
|
|
308
322
|
return { index: node.index, signingKey };
|
|
309
323
|
});
|
|
310
324
|
}
|
|
325
|
+
var typeHash = (signature) => keccak_256(utf8(signature));
|
|
326
|
+
var EIP712_DOMAIN_TYPEHASH = typeHash(
|
|
327
|
+
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
|
|
328
|
+
);
|
|
329
|
+
var TRANSFER_WITH_AUTHORIZATION_TYPEHASH = typeHash(
|
|
330
|
+
"TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
|
|
331
|
+
);
|
|
332
|
+
function word(bytes) {
|
|
333
|
+
if (bytes.length > 32) throw new RangeError("ABI word overflow");
|
|
334
|
+
const out = new Uint8Array(32);
|
|
335
|
+
out.set(bytes, 32 - bytes.length);
|
|
336
|
+
return out;
|
|
337
|
+
}
|
|
338
|
+
function addressWord(address3) {
|
|
339
|
+
const bytes = hexToBytes(address3);
|
|
340
|
+
if (bytes.length !== 20) throw new RangeError(`Not a 20-byte address: ${address3}`);
|
|
341
|
+
return word(bytes);
|
|
342
|
+
}
|
|
343
|
+
function uintWord(value) {
|
|
344
|
+
const n = typeof value === "bigint" ? value : BigInt(value);
|
|
345
|
+
if (n < 0n) throw new RangeError(`Not an unsigned integer: ${value}`);
|
|
346
|
+
const hex = n.toString(16);
|
|
347
|
+
return word(hexToBytes(hex.length % 2 === 0 ? hex : "0" + hex));
|
|
348
|
+
}
|
|
349
|
+
function bytes32Word(value) {
|
|
350
|
+
const bytes = hexToBytes(value);
|
|
351
|
+
if (bytes.length !== 32) throw new RangeError(`Not a 32-byte value: ${value}`);
|
|
352
|
+
return bytes;
|
|
353
|
+
}
|
|
354
|
+
function domainSeparator(domain) {
|
|
355
|
+
return keccak_256(
|
|
356
|
+
concatBytes(
|
|
357
|
+
EIP712_DOMAIN_TYPEHASH,
|
|
358
|
+
keccak_256(utf8(domain.name)),
|
|
359
|
+
keccak_256(utf8(domain.version)),
|
|
360
|
+
uintWord(BigInt(domain.chainId)),
|
|
361
|
+
addressWord(domain.verifyingContract)
|
|
362
|
+
)
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
function transferWithAuthorizationHash(auth) {
|
|
366
|
+
return keccak_256(
|
|
367
|
+
concatBytes(
|
|
368
|
+
TRANSFER_WITH_AUTHORIZATION_TYPEHASH,
|
|
369
|
+
addressWord(auth.from),
|
|
370
|
+
addressWord(auth.to),
|
|
371
|
+
uintWord(auth.value),
|
|
372
|
+
uintWord(auth.validAfter),
|
|
373
|
+
uintWord(auth.validBefore),
|
|
374
|
+
bytes32Word(auth.nonce)
|
|
375
|
+
)
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
function transferWithAuthorizationDigest(domain, auth) {
|
|
379
|
+
return keccak_256(
|
|
380
|
+
concatBytes(
|
|
381
|
+
Uint8Array.from([25, 1]),
|
|
382
|
+
domainSeparator(domain),
|
|
383
|
+
transferWithAuthorizationHash(auth)
|
|
384
|
+
)
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
function toChecksumAddress(address3) {
|
|
388
|
+
const lower = bytesToHex(hexToBytes(address3));
|
|
389
|
+
if (lower.length !== 40) throw new RangeError(`Not a 20-byte address: ${address3}`);
|
|
390
|
+
const digest = bytesToHex(keccak_256(utf8(lower)));
|
|
391
|
+
let out = "0x";
|
|
392
|
+
for (let i = 0; i < lower.length; i++) {
|
|
393
|
+
out += parseInt(digest[i], 16) >= 8 ? lower[i].toUpperCase() : lower[i];
|
|
394
|
+
}
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
397
|
+
function evmAddressFromPrivateKey(privateKey) {
|
|
398
|
+
const key = typeof privateKey === "string" ? hexToBytes(privateKey) : privateKey;
|
|
399
|
+
if (key.length !== 32) throw new RangeError("EVM private key must be 32 bytes");
|
|
400
|
+
const uncompressed = secp256k1.getPublicKey(key, false);
|
|
401
|
+
return toChecksumAddress(bytesToHex0x(keccak_256(uncompressed.subarray(1)).subarray(12)));
|
|
402
|
+
}
|
|
403
|
+
function createEvmSignerFromPrivateKey(privateKey) {
|
|
404
|
+
const key = typeof privateKey === "string" ? hexToBytes(privateKey) : privateKey;
|
|
405
|
+
const address3 = evmAddressFromPrivateKey(key);
|
|
406
|
+
return {
|
|
407
|
+
address: address3,
|
|
408
|
+
async signDigest(digest) {
|
|
409
|
+
if (digest.length !== 32) throw new RangeError("Digest must be 32 bytes");
|
|
410
|
+
const signed = secp256k1.sign(digest, key, { prehash: false, format: "recovered" });
|
|
411
|
+
const out = new Uint8Array(65);
|
|
412
|
+
out.set(signed.subarray(1), 0);
|
|
413
|
+
out[64] = 27 + signed[0];
|
|
414
|
+
return out;
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// src/gateway/x402.ts
|
|
420
|
+
var NETWORKS = {
|
|
421
|
+
"eip155:8453": { chainId: 8453, usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
|
|
422
|
+
"eip155:84532": { chainId: 84532, usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e" },
|
|
423
|
+
// x402 v1 network names.
|
|
424
|
+
base: { chainId: 8453, usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" },
|
|
425
|
+
"base-sepolia": { chainId: 84532, usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e" }
|
|
426
|
+
};
|
|
427
|
+
var UpstreamPaymentRequiredError = class extends Error {
|
|
428
|
+
constructor(quote, message) {
|
|
429
|
+
super(
|
|
430
|
+
message ?? `API source requires payment for up to ${quote.eligibleSetSize} fetches: ${quote.resource}`
|
|
431
|
+
);
|
|
432
|
+
this.quote = quote;
|
|
433
|
+
this.name = "UpstreamPaymentRequiredError";
|
|
434
|
+
}
|
|
435
|
+
quote;
|
|
436
|
+
};
|
|
437
|
+
function eligibleSetSize(signaturesRequired, registry) {
|
|
438
|
+
return effectiveSelectionSize(
|
|
439
|
+
signaturesRequired,
|
|
440
|
+
registry.redundancyBuffer,
|
|
441
|
+
registry.nodeCount
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
function parseUpstreamQuote(envelope) {
|
|
445
|
+
if (!envelope || typeof envelope !== "object") return null;
|
|
446
|
+
const extensions = envelope.extensions;
|
|
447
|
+
if (!extensions || typeof extensions !== "object") return null;
|
|
448
|
+
const quote = extensions.upstream;
|
|
449
|
+
if (!quote || typeof quote !== "object") return null;
|
|
450
|
+
return typeof quote.eligibleSetSize === "number" ? quote : null;
|
|
451
|
+
}
|
|
452
|
+
function selectTerms(envelope, resource, assetDomain) {
|
|
453
|
+
const version = envelope.x402Version === 1 ? 1 : 2;
|
|
454
|
+
const offers = Array.isArray(envelope.accepts) ? envelope.accepts : [];
|
|
455
|
+
if (offers.length === 0) {
|
|
456
|
+
throw new Error(`Source 402 for ${resource} advertised no payment terms`);
|
|
457
|
+
}
|
|
458
|
+
const supported = offers.find(
|
|
459
|
+
(o) => o.scheme === "exact" && NETWORKS[String(o.network)] !== void 0
|
|
460
|
+
);
|
|
461
|
+
if (!supported) {
|
|
462
|
+
const seen = offers.map((o) => `${o.scheme}/${o.network}`).join(", ");
|
|
463
|
+
throw new Error(
|
|
464
|
+
`Source ${resource} requires an unsupported payment scheme or network (${seen}); this SDK signs exact payments on Base USDC only`
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
const network = NETWORKS[String(supported.network)];
|
|
468
|
+
const asset = String(supported.asset ?? "");
|
|
469
|
+
if (asset.toLowerCase() !== network.usdc.toLowerCase()) {
|
|
470
|
+
throw new Error(
|
|
471
|
+
`Source ${resource} asks to be paid in ${asset} on ${supported.network}; this SDK signs USDC (${network.usdc}) only`
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
const domain = assetDomain ?? (supported.extra?.name && supported.extra?.version ? { name: String(supported.extra.name), version: String(supported.extra.version) } : void 0);
|
|
475
|
+
if (!domain) {
|
|
476
|
+
throw new Error(
|
|
477
|
+
`Source ${resource} omitted extra.name/extra.version for ${asset}; supply sourcePayment.assetDomain to sign against it`
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
const amount = String(supported.amount ?? supported.maxAmountRequired ?? "");
|
|
481
|
+
if (!/^\d+$/.test(amount)) {
|
|
482
|
+
throw new Error(`Source ${resource} quoted a non-integer price: ${amount}`);
|
|
483
|
+
}
|
|
484
|
+
const payTo = String(supported.payTo ?? "");
|
|
485
|
+
if (!payTo) throw new Error(`Source ${resource} omitted payTo`);
|
|
486
|
+
return {
|
|
487
|
+
x402Version: version,
|
|
488
|
+
// Echoed verbatim in the signed payload, so it must stay the source's own object.
|
|
489
|
+
requirements: supported,
|
|
490
|
+
network: String(supported.network),
|
|
491
|
+
chainId: network.chainId,
|
|
492
|
+
asset,
|
|
493
|
+
payTo,
|
|
494
|
+
amount,
|
|
495
|
+
maxTimeoutSeconds: Number(supported.maxTimeoutSeconds ?? 60),
|
|
496
|
+
domain,
|
|
497
|
+
resource
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
function decodeEnvelope(headerValue, body) {
|
|
501
|
+
if (headerValue) {
|
|
502
|
+
try {
|
|
503
|
+
return JSON.parse(
|
|
504
|
+
new TextDecoder().decode(base64ToBytes(headerValue))
|
|
505
|
+
);
|
|
506
|
+
} catch {
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return JSON.parse(body);
|
|
510
|
+
}
|
|
511
|
+
function validateSuppliedTerms(terms, resource, assetDomain) {
|
|
512
|
+
return selectTerms(
|
|
513
|
+
{
|
|
514
|
+
x402Version: terms.x402Version,
|
|
515
|
+
accepts: [terms.requirements]
|
|
516
|
+
},
|
|
517
|
+
resource,
|
|
518
|
+
assetDomain
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
async function probeSource(apiConfig, options = {}) {
|
|
522
|
+
const resolved = options.secrets ? resolveAPIConfig(apiConfig, options.secrets) : apiConfig;
|
|
523
|
+
const init = {
|
|
524
|
+
method: resolved.method ?? "GET",
|
|
525
|
+
headers: resolved.headers ?? {}
|
|
526
|
+
};
|
|
527
|
+
let res;
|
|
528
|
+
if (options.timeoutMs === void 0) {
|
|
529
|
+
res = await fetch(resolved.url, init);
|
|
530
|
+
} else {
|
|
531
|
+
const controller = new AbortController();
|
|
532
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
533
|
+
try {
|
|
534
|
+
res = await fetch(resolved.url, { ...init, signal: controller.signal });
|
|
535
|
+
} finally {
|
|
536
|
+
clearTimeout(timer);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (res.status !== 402) return null;
|
|
540
|
+
return selectTerms(
|
|
541
|
+
decodeEnvelope(res.headers.get("PAYMENT-REQUIRED"), await res.text()),
|
|
542
|
+
apiConfig.url,
|
|
543
|
+
options.assetDomain
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
async function signSourcePayments(terms, signer, count) {
|
|
547
|
+
if (!Number.isInteger(count) || count < 1) {
|
|
548
|
+
throw new RangeError(`Cannot sign ${count} source payments`);
|
|
549
|
+
}
|
|
550
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
551
|
+
const validAfter = String(now - 600);
|
|
552
|
+
const validBefore = String(now + Math.max(terms.maxTimeoutSeconds, 60));
|
|
553
|
+
const payments = [];
|
|
554
|
+
for (let i = 0; i < count; i++) {
|
|
555
|
+
const authorization = {
|
|
556
|
+
from: toChecksumAddress(signer.address),
|
|
557
|
+
to: toChecksumAddress(terms.payTo),
|
|
558
|
+
value: terms.amount,
|
|
559
|
+
validAfter,
|
|
560
|
+
validBefore,
|
|
561
|
+
nonce: bytesToHex0x(randomBytes(32))
|
|
562
|
+
};
|
|
563
|
+
const digest = transferWithAuthorizationDigest(
|
|
564
|
+
{
|
|
565
|
+
name: terms.domain.name,
|
|
566
|
+
version: terms.domain.version,
|
|
567
|
+
chainId: terms.chainId,
|
|
568
|
+
verifyingContract: terms.asset
|
|
569
|
+
},
|
|
570
|
+
authorization
|
|
571
|
+
);
|
|
572
|
+
const signature = bytesToHex0x(await signer.signDigest(digest));
|
|
573
|
+
const payload = terms.x402Version === 1 ? {
|
|
574
|
+
x402Version: 1,
|
|
575
|
+
scheme: "exact",
|
|
576
|
+
network: terms.network,
|
|
577
|
+
payload: { signature, authorization }
|
|
578
|
+
} : {
|
|
579
|
+
x402Version: 2,
|
|
580
|
+
accepted: terms.requirements,
|
|
581
|
+
payload: { signature, authorization }
|
|
582
|
+
};
|
|
583
|
+
payments.push(bytesToBase64(utf8(JSON.stringify(payload))));
|
|
584
|
+
}
|
|
585
|
+
return payments;
|
|
586
|
+
}
|
|
311
587
|
var SEED_GATEWAY = utf8("molpha_gateway");
|
|
312
588
|
var addressEncoder = getAddressEncoder();
|
|
313
589
|
function normalizeEndpoint(input) {
|
|
@@ -392,8 +668,24 @@ var MolphaGateway = class {
|
|
|
392
668
|
}
|
|
393
669
|
/** Tries endpoints in order; returns the first node list it can fetch. */
|
|
394
670
|
async getNodes() {
|
|
671
|
+
return (await this.getNodesInfo()).nodes;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* `GET /v1/nodes` — the peer set plus the gateway's view of the registry
|
|
675
|
+
* selection policy, which sizes the eligible set a paid source must fund.
|
|
676
|
+
*
|
|
677
|
+
* The `registry` block is advisory: it is whatever the gateway read from the
|
|
678
|
+
* chain, and is absent on older gateways or when that read failed. Prefer the
|
|
679
|
+
* on-chain read (`MolphaSolanaClient.getRegistrySelectionConfig`) whenever a
|
|
680
|
+
* Solana connection is available — `requestSignedData` already does.
|
|
681
|
+
*/
|
|
682
|
+
async getNodesInfo() {
|
|
395
683
|
const data = await this.firstReachableData("/v1/nodes");
|
|
396
|
-
|
|
684
|
+
if (Array.isArray(data)) return { nodes: data };
|
|
685
|
+
return {
|
|
686
|
+
nodes: data.nodes,
|
|
687
|
+
...data.registry ? { registry: data.registry } : {}
|
|
688
|
+
};
|
|
397
689
|
}
|
|
398
690
|
async isHealthy() {
|
|
399
691
|
for (const endpoint of this.endpoints) {
|
|
@@ -454,12 +746,17 @@ var MolphaGateway = class {
|
|
|
454
746
|
* read does not report `nodeCount`). Supply `opts.context` (e.g. from
|
|
455
747
|
* {@link prepareContext}) to reuse cached inputs and skip those fetches — a
|
|
456
748
|
* fully-populated context collapses the call to a single POST round.
|
|
749
|
+
*
|
|
750
|
+
* When the API source is itself x402-paywalled, pass `opts.sourcePayment` to
|
|
751
|
+
* fund it; without that, such a source throws
|
|
752
|
+
* {@link UpstreamPaymentRequiredError} carrying the gateway's quote.
|
|
457
753
|
*/
|
|
458
754
|
async requestSignedData(opts) {
|
|
459
755
|
const {
|
|
460
756
|
apiConfig,
|
|
461
757
|
signer,
|
|
462
758
|
encrypt,
|
|
759
|
+
sourcePayment,
|
|
463
760
|
maxAge = 60,
|
|
464
761
|
maxRetries = 15,
|
|
465
762
|
timeoutMs = 5e3
|
|
@@ -494,9 +791,33 @@ var MolphaGateway = class {
|
|
|
494
791
|
if (nodeCount === void 0) {
|
|
495
792
|
throw new Error("Round context resolved neither nodeCount nor nodes");
|
|
496
793
|
}
|
|
794
|
+
let terms = null;
|
|
795
|
+
let authorizations = 0;
|
|
796
|
+
let requoted = false;
|
|
797
|
+
if (sourcePayment) {
|
|
798
|
+
terms = sourcePayment.terms ? validateSuppliedTerms(
|
|
799
|
+
sourcePayment.terms,
|
|
800
|
+
requestApiConfig.url,
|
|
801
|
+
sourcePayment.assetDomain
|
|
802
|
+
) : await probeSource(apiConfig, {
|
|
803
|
+
...encrypt ? { secrets: encrypt.secrets } : {},
|
|
804
|
+
...sourcePayment.assetDomain ? { assetDomain: sourcePayment.assetDomain } : {},
|
|
805
|
+
timeoutMs
|
|
806
|
+
});
|
|
807
|
+
if (terms) {
|
|
808
|
+
authorizations = effectiveSelectionSize(
|
|
809
|
+
signaturesRequired,
|
|
810
|
+
redundancyBuffer,
|
|
811
|
+
nodeCount
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
497
815
|
let lastError;
|
|
816
|
+
let lastTimestamp = 0;
|
|
498
817
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
499
|
-
|
|
818
|
+
let timestamp = Math.floor(Date.now() / 1e3);
|
|
819
|
+
if (timestamp <= lastTimestamp) timestamp = lastTimestamp + 1;
|
|
820
|
+
lastTimestamp = timestamp;
|
|
500
821
|
const seed = deriveSelectionSeed(sourceIdBytes, registryVersion, timestamp);
|
|
501
822
|
const groupSize = effectiveSelectionSize(signaturesRequired, redundancyBuffer, nodeCount);
|
|
502
823
|
const bitmap = deriveGroupBitmap(seed, nodeCount, groupSize);
|
|
@@ -515,6 +836,14 @@ var MolphaGateway = class {
|
|
|
515
836
|
}
|
|
516
837
|
encKeyBundle = encryptForNodes(requestApiConfig, encrypt.secrets, selected);
|
|
517
838
|
}
|
|
839
|
+
let sourcePayments;
|
|
840
|
+
if (terms && sourcePayment && authorizations > 0) {
|
|
841
|
+
sourcePayments = await signSourcePayments(
|
|
842
|
+
terms,
|
|
843
|
+
sourcePayment.signer,
|
|
844
|
+
authorizations
|
|
845
|
+
);
|
|
846
|
+
}
|
|
518
847
|
const baseBody = {
|
|
519
848
|
sourceId,
|
|
520
849
|
registryVersion,
|
|
@@ -526,6 +855,8 @@ var MolphaGateway = class {
|
|
|
526
855
|
apiConfig: requestApiConfig
|
|
527
856
|
};
|
|
528
857
|
if (encKeyBundle) baseBody.encKeyBundle = encKeyBundle;
|
|
858
|
+
if (sourcePayments) baseBody.sourcePayments = sourcePayments;
|
|
859
|
+
let requote = false;
|
|
529
860
|
for (const endpoint of this.endpoints) {
|
|
530
861
|
try {
|
|
531
862
|
let authSig = ZERO_AUTH_SIG;
|
|
@@ -547,6 +878,55 @@ var MolphaGateway = class {
|
|
|
547
878
|
body,
|
|
548
879
|
timeoutMs
|
|
549
880
|
);
|
|
881
|
+
if (res.status === 402) {
|
|
882
|
+
const quote = parseUpstreamQuote(
|
|
883
|
+
await res.json().catch(() => null)
|
|
884
|
+
);
|
|
885
|
+
if (!quote) {
|
|
886
|
+
throw new GatewayError(
|
|
887
|
+
"Gateway requires payment but returned no upstream source quote",
|
|
888
|
+
402
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
if (!sourcePayment) throw new UpstreamPaymentRequiredError(quote);
|
|
892
|
+
if (terms && requoted && authorizations >= quote.eligibleSetSize) {
|
|
893
|
+
throw new UpstreamPaymentRequiredError(
|
|
894
|
+
quote,
|
|
895
|
+
`Source payment was not accepted for ${quote.resource}: ${quote.error ?? "no detail"}`
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
requoted = true;
|
|
899
|
+
if (quote.eligibleSetSize !== groupSize) {
|
|
900
|
+
throw new GatewayError(
|
|
901
|
+
`Gateway upstream quote eligibleSetSize ${quote.eligibleSetSize} does not match this round's selection size ${groupSize} (min(signaturesRequired + redundancyBuffer, nodeCount))`,
|
|
902
|
+
402
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
authorizations = groupSize;
|
|
906
|
+
if (!terms) {
|
|
907
|
+
try {
|
|
908
|
+
terms = await probeSource(apiConfig, {
|
|
909
|
+
...encrypt ? { secrets: encrypt.secrets } : {},
|
|
910
|
+
...sourcePayment.assetDomain ? { assetDomain: sourcePayment.assetDomain } : {},
|
|
911
|
+
timeoutMs
|
|
912
|
+
});
|
|
913
|
+
} catch (err) {
|
|
914
|
+
throw new UpstreamPaymentRequiredError(
|
|
915
|
+
quote,
|
|
916
|
+
`Cannot pay ${quote.resource}: ${err instanceof Error ? err.message : String(err)}`
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (!terms) {
|
|
921
|
+
throw new UpstreamPaymentRequiredError(
|
|
922
|
+
quote,
|
|
923
|
+
`Gateway reports ${quote.resource} is paywalled but the source returned no payment terms`
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
lastError = new UpstreamPaymentRequiredError(quote);
|
|
927
|
+
requote = true;
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
550
930
|
const errorDetail = !res.ok ? await parseGatewayErrorDetail(res) : void 0;
|
|
551
931
|
if (res.status === 400 || res.status === 401) {
|
|
552
932
|
throw new GatewayError(
|
|
@@ -581,12 +961,14 @@ var MolphaGateway = class {
|
|
|
581
961
|
}
|
|
582
962
|
lastError = new Error(`Gateway returned status: ${json.status}`);
|
|
583
963
|
} catch (err) {
|
|
584
|
-
if (err instanceof
|
|
964
|
+
if (err instanceof UpstreamPaymentRequiredError) throw err;
|
|
965
|
+
if (err instanceof GatewayError && (err.status === 400 || err.status === 401 || err.status === 402)) {
|
|
585
966
|
throw err;
|
|
586
967
|
}
|
|
587
968
|
lastError = err;
|
|
588
969
|
}
|
|
589
970
|
}
|
|
971
|
+
if (requote) continue;
|
|
590
972
|
}
|
|
591
973
|
throw lastError instanceof Error ? lastError : new Error("Gateway round failed after retries");
|
|
592
974
|
}
|
|
@@ -11353,6 +11735,6 @@ var MolphaSDK = class {
|
|
|
11353
11735
|
}
|
|
11354
11736
|
};
|
|
11355
11737
|
|
|
11356
|
-
export { DEFAULT_GATEWAY_ENDPOINT, GatewayError, MESSAGE_PREFIX, MOLPHA_IDL, MOLPHA_PROGRAM_ADDRESS, MOLPHA_PROGRAM_ID, MOLPHA_VERIFIER_ABI, MOLPHA_VERIFIER_ADDRESS, MOLPHA_VERIFIER_STARKNET_ADDRESSES, MOLPHA_VERIFIER_STARKNET_SEPOLIA, MolphaGateway, MolphaSDK, MolphaSolanaClient, PlanType, REQUEST_AUTH_DOMAIN, addressToBytes, attestationMessageHash, attestationMessageHashFromResult, bigIntFromBytesBe, bitmapBitSet, bitmapToIndices, buildEvmVerifierArgs, buildStarknetVerifierArgs, buildSubmitAttestationArgs, bytesToHex, bytesToHex0x, canonicalizeAPIConfig, commitmentAddressToStarknetFelt, concatBytes, deriveApiConfigHash, deriveGatewayPda, deriveGatewayPdaAddress, deriveGroupBitmap, deriveSelectionBitmap, deriveSelectionSeed, deriveSourceId, deriveSourceIdString, effectiveSelectionSize, encodeRequestAuth, ensureLength, feedPda, gatewayPda, getMolphaStarknetVerifierAddress, hashRequestAuth, hexToBytes, nodePda, normalizeEndpoint, normalizeSecp256k1PublicKeyHex, parseGatewayInfo, planIdFromVariant, planPda, planVariant, protocolConfigPda, registryPda, registryStatePda, resolveRemainingAccounts, secp256k1PublicKeyFromCoordinates, selectedIndices, signersBitmapToDecimal, signersBitmapToStarknetUint256, signersBitmapToUint256, subscriptionPda, toFixedBytes, toFixedHex, u256beFromBigInt, u32be, u32le, u64be, u64le, utf8 };
|
|
11738
|
+
export { DEFAULT_GATEWAY_ENDPOINT, EIP712_DOMAIN_TYPEHASH, GatewayError, MESSAGE_PREFIX, MOLPHA_IDL, MOLPHA_PROGRAM_ADDRESS, MOLPHA_PROGRAM_ID, MOLPHA_VERIFIER_ABI, MOLPHA_VERIFIER_ADDRESS, MOLPHA_VERIFIER_STARKNET_ADDRESSES, MOLPHA_VERIFIER_STARKNET_SEPOLIA, MolphaGateway, MolphaSDK, MolphaSolanaClient, PlanType, REQUEST_AUTH_DOMAIN, TRANSFER_WITH_AUTHORIZATION_TYPEHASH, UpstreamPaymentRequiredError, addressToBytes, attestationMessageHash, attestationMessageHashFromResult, base64ToBytes, bigIntFromBytesBe, bitmapBitSet, bitmapToIndices, buildEvmVerifierArgs, buildStarknetVerifierArgs, buildSubmitAttestationArgs, bytesToBase64, bytesToHex, bytesToHex0x, canonicalizeAPIConfig, commitmentAddressToStarknetFelt, concatBytes, createEvmSignerFromPrivateKey, deriveApiConfigHash, deriveGatewayPda, deriveGatewayPdaAddress, deriveGroupBitmap, deriveSelectionBitmap, deriveSelectionSeed, deriveSourceId, deriveSourceIdString, domainSeparator, effectiveSelectionSize, eligibleSetSize, encodeRequestAuth, ensureLength, evmAddressFromPrivateKey, feedPda, gatewayPda, getMolphaStarknetVerifierAddress, hashRequestAuth, hexToBytes, nodePda, normalizeEndpoint, normalizeSecp256k1PublicKeyHex, parseGatewayInfo, parseUpstreamQuote, planIdFromVariant, planPda, planVariant, probeSource, protocolConfigPda, registryPda, registryStatePda, resolveRemainingAccounts, secp256k1PublicKeyFromCoordinates, selectedIndices, signSourcePayments, signersBitmapToDecimal, signersBitmapToStarknetUint256, signersBitmapToUint256, subscriptionPda, toChecksumAddress, toFixedBytes, toFixedHex, transferWithAuthorizationDigest, transferWithAuthorizationHash, u256beFromBigInt, u32be, u32le, u64be, u64le, utf8, validateSuppliedTerms };
|
|
11357
11739
|
//# sourceMappingURL=index.js.map
|
|
11358
11740
|
//# sourceMappingURL=index.js.map
|