@dvmkit/sdk 0.6.0-rc.1 → 0.7.0-rc.10
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 +39 -2
- package/dist/{chunk-PLG4XER6.js → chunk-2NUFE2PG.js} +47 -5
- package/dist/{chunk-7ZUKL4IV.js → chunk-3E4C6W7W.js} +16 -5
- package/dist/{chunk-HHBDBMEO.js → chunk-53SNRGQQ.js} +375 -158
- package/dist/{chunk-IWQHUSMO.js → chunk-62FI3NJF.js} +78 -2
- package/dist/chunk-6HJEVCVI.js +17 -0
- package/dist/chunk-A262WVYX.js +6 -0
- package/dist/{chunk-RLTSCKRI.js → chunk-BPYMEMQX.js} +50 -3
- package/dist/{chunk-IV6Q7NRW.js → chunk-C5RIQWG4.js} +1 -1
- package/dist/{chunk-GAOAYHZA.js → chunk-FBQVOOYF.js} +37 -6
- package/dist/{chunk-Z4ZT5LNT.js → chunk-GEI4MAXE.js} +3 -3
- package/dist/{chunk-FYRR2UEZ.js → chunk-GLIAR7RN.js} +1 -1
- package/dist/{chunk-X7EZ5CLI.js → chunk-HCATFJDD.js} +3 -3
- package/dist/{chunk-BYCEKO65.js → chunk-HPCXF3DV.js} +220 -32
- package/dist/{chunk-JH3SX3LY.js → chunk-IRXIH775.js} +6 -6
- package/dist/{chunk-QR2EF2NI.js → chunk-KCQDXIJU.js} +1 -42
- package/dist/chunk-MDW7ZR7V.js +47 -0
- package/dist/{chunk-KA6VN5FK.js → chunk-MQYM4T66.js} +3 -3
- package/dist/{chunk-P6QON7ER.js → chunk-NV7Z7377.js} +1 -1
- package/dist/{chunk-OQA7IHI4.js → chunk-OBBVDKLE.js} +484 -234
- package/dist/{chunk-EQLA4FFY.js → chunk-OHUXCAOM.js} +17 -6
- package/dist/{chunk-FI4CST2D.js → chunk-PZ5IAWFD.js} +5 -7
- package/dist/{chunk-IXR5RFK7.js → chunk-R3TQSXWT.js} +191 -5
- package/dist/{chunk-VHNPVGSA.js → chunk-T5DIXOLR.js} +3 -3
- package/dist/{chunk-RCM3P2HE.js → chunk-UKD3R2KU.js} +55 -4
- package/dist/chunk-WMGXJQI3.js +120 -0
- package/dist/{chunk-N5RZ5HVB.js → chunk-X6S2CHFM.js} +2 -2
- package/dist/{chunk-ETXDTUJO.js → chunk-ZCNPIILZ.js} +112 -1
- package/dist/{content-retention-BTGSQRfP.d.ts → content-retention-D2K4MKNO.d.ts} +1 -1
- package/dist/{credit-ledger-MI2H7NEC.js → credit-ledger-MFIIOSZH.js} +4 -5
- package/dist/{credit-menu-BAsrRu3z.d.ts → credit-menu-D2t1-Tf6.d.ts} +13 -6
- package/dist/{fx-BgDmyTdd.d.ts → fx-Ql4nvdbh.d.ts} +10 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +248 -16
- package/dist/internal/caller.d.ts +4586 -7318
- package/dist/internal/caller.js +4431 -8127
- package/dist/internal/index.js +1 -1
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +30 -33
- package/dist/{job-store-BVeF5_Jq.d.ts → job-store-DCvJQUX0.d.ts} +1 -1
- package/dist/{lightning-backend-40fIzz1W.d.ts → lightning-backend-CY5ML3km.d.ts} +4 -2
- package/dist/memory-credit-ledger-44NE4PZC.js +11 -0
- package/dist/{mpp-setup-RF5FXGGV.js → mpp-setup-HRWUBULX.js} +4 -2
- package/dist/{payout-reporter-3Y2U55ZX.js → payout-reporter-7P66T77I.js} +6 -4
- package/dist/{postgres-consumed-credential-store-BUVCAPLS.js → postgres-consumed-credential-store-IDGPFKIL.js} +3 -3
- package/dist/{postgres-job-store-VHLQBJZC.js → postgres-job-store-UKNJ2F6Z.js} +2 -2
- package/dist/{postgres-replay-store-ARZSQ45X.js → postgres-replay-store-PMA4ADXN.js} +2 -2
- package/dist/{pricing-XT2IAPNE.js → pricing-52XJHJ6K.js} +12 -12
- package/dist/{revenue-reporter-MAERPYGK.js → revenue-reporter-HV7RMS54.js} +2 -2
- package/dist/server/index.d.ts +12 -11
- package/dist/server/index.js +49 -53
- package/dist/{step-cache-CPdH1hei.d.ts → step-cache-BOWAn_BH.d.ts} +84 -7
- package/dist/{tempo-charge-store-Q3D7KYMH.js → tempo-charge-store-P2Z4RMU7.js} +2 -2
- package/dist/{tempo-session-store-ZRNCOX7P.js → tempo-session-store-VSP7KLBS.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +7 -6
- package/dist/{usd-AWlrwlM5.d.ts → usd-MAtMp3DB.d.ts} +1 -1
- package/dist/{x402-R6HPBY5D.js → x402-3IQ3HXSG.js} +9 -29
- package/package.json +3 -2
- package/dist/chunk-AT6V3SY7.js +0 -102
- package/dist/chunk-B2IROPQF.js +0 -1844
- package/dist/chunk-CZULM42S.js +0 -143
- package/dist/chunk-GFY5FRX3.js +0 -218
- package/dist/chunk-HCLVYZUZ.js +0 -244
- package/dist/chunk-LE74UEV7.js +0 -1071
- package/dist/chunk-LIRAHP7B.js +0 -53
- package/dist/chunk-MZRJR2CW.js +0 -776
- package/dist/chunk-OFVV37XC.js +0 -57
- package/dist/chunk-PAIM66YA.js +0 -347
- package/dist/chunk-UOCZXO2Z.js +0 -1663
- package/dist/memory-credit-ledger-W2BAUYJP.js +0 -12
- package/dist/tempo-lifecycle-ZBBLFBMH.js +0 -15
- package/dist/tempo-wallet-B5XXV3YH.js +0 -40
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
TEMPO_MODERATO_CHAIN_ID,
|
|
3
|
+
TEMPO_MODERATO_RPC,
|
|
4
|
+
advertisedMethods,
|
|
5
|
+
challengeMeta,
|
|
6
|
+
installHostedTempoChargeGuard,
|
|
7
|
+
installHostedTempoCloseGuard,
|
|
8
|
+
isTempoInsufficientFundsError,
|
|
9
|
+
resolveTempoNetwork
|
|
10
|
+
} from "./chunk-R3TQSXWT.js";
|
|
11
|
+
import {
|
|
12
|
+
x402EarnedCeiling
|
|
13
|
+
} from "./chunk-FBQVOOYF.js";
|
|
6
14
|
import {
|
|
7
15
|
createX402FacilitatorAuthHeaders,
|
|
8
16
|
createX402FacilitatorClient,
|
|
17
|
+
paymentFailureStage,
|
|
9
18
|
settleWithFacilitator,
|
|
10
|
-
verifyWithFacilitator
|
|
11
|
-
|
|
19
|
+
verifyWithFacilitator,
|
|
20
|
+
withPaymentDiagnostics,
|
|
21
|
+
withPaymentStage
|
|
22
|
+
} from "./chunk-2NUFE2PG.js";
|
|
12
23
|
import {
|
|
13
24
|
MemoryCreditLedger
|
|
14
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-GLIAR7RN.js";
|
|
15
26
|
import {
|
|
16
27
|
PostgresJobStore
|
|
17
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-OHUXCAOM.js";
|
|
18
29
|
import {
|
|
19
30
|
parseStoreValue
|
|
20
31
|
} from "./chunk-YG7G4DPZ.js";
|
|
@@ -25,7 +36,7 @@ import {
|
|
|
25
36
|
humanizeZodIssues,
|
|
26
37
|
signedRequestInput,
|
|
27
38
|
zodIssuesOf
|
|
28
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-X6S2CHFM.js";
|
|
29
40
|
import {
|
|
30
41
|
MemoryJobStore,
|
|
31
42
|
UNCAPPABLE_ASK_TOTAL,
|
|
@@ -34,7 +45,7 @@ import {
|
|
|
34
45
|
isJobRetentionStore,
|
|
35
46
|
isReceiptIssuingStore,
|
|
36
47
|
isStreamableJobStore
|
|
37
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-C5RIQWG4.js";
|
|
38
49
|
import {
|
|
39
50
|
ContentHoldError,
|
|
40
51
|
JobCancelledError,
|
|
@@ -53,23 +64,28 @@ import {
|
|
|
53
64
|
ADMIN_AUTH_CLOCK_SKEW_SECONDS,
|
|
54
65
|
ADMIN_AUTH_NONCE_TTL_SECONDS,
|
|
55
66
|
ADMIN_STATE_UNAVAILABLE,
|
|
67
|
+
IMPLICIT_CREDIT_TTL_MS,
|
|
68
|
+
JOB_IDENTITY_HEADER,
|
|
56
69
|
TEMPO_SESSION_UPDATED_REASON,
|
|
57
70
|
X402_BATCH_CHANNEL_ABI,
|
|
58
71
|
attestedDvmIdentity,
|
|
59
72
|
buildAdminChallenge,
|
|
60
73
|
checkMintHealth,
|
|
74
|
+
computeResultHash,
|
|
61
75
|
createMonotonicClock,
|
|
76
|
+
formatStaleness,
|
|
62
77
|
getWallet,
|
|
78
|
+
isJobIdentityValue,
|
|
63
79
|
isPublicRequestId,
|
|
64
|
-
isTestMintUrl,
|
|
65
80
|
isX402SettlementReconciliationReason,
|
|
66
|
-
normaliseMintUrl,
|
|
67
81
|
parseTraceparent,
|
|
68
82
|
receiptPubkeyFromSecret,
|
|
83
|
+
signDrainReceipt,
|
|
84
|
+
signFundingReceipt,
|
|
85
|
+
signReceipt,
|
|
69
86
|
toLockPubkey,
|
|
70
|
-
verifyCashuToken,
|
|
71
87
|
verifyChallenge
|
|
72
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-OBBVDKLE.js";
|
|
73
89
|
import {
|
|
74
90
|
X402_BATCH_SETTLEMENT_SCHEME,
|
|
75
91
|
X402_DEFAULT_FACILITATOR,
|
|
@@ -82,38 +98,28 @@ import {
|
|
|
82
98
|
encodePaymentRequiredHeader,
|
|
83
99
|
encodeSettleResponseHeader,
|
|
84
100
|
exactEvmAuthorization,
|
|
85
|
-
paymentRequiredV2FromV1,
|
|
86
|
-
x402NetworkToCaip2
|
|
87
|
-
} from "./chunk-IWQHUSMO.js";
|
|
88
|
-
import {
|
|
89
|
-
IMPLICIT_CREDIT_TTL_MS,
|
|
90
|
-
computeResultHash,
|
|
91
|
-
formatStaleness,
|
|
92
101
|
msatsToUsd,
|
|
93
102
|
msatsToUsdc,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
} from "./chunk-
|
|
99
|
-
import {
|
|
100
|
-
resolveRpcOverride
|
|
101
|
-
} from "./chunk-CZULM42S.js";
|
|
103
|
+
paymentRequiredV2FromV1,
|
|
104
|
+
resolveRpcOverride,
|
|
105
|
+
usdcToMsats,
|
|
106
|
+
x402NetworkToCaip2
|
|
107
|
+
} from "./chunk-62FI3NJF.js";
|
|
102
108
|
import {
|
|
103
109
|
RAIL_REFUNDABLE,
|
|
104
110
|
canonicalRequestPath,
|
|
111
|
+
canonicalize,
|
|
105
112
|
isZodSchema
|
|
106
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-UKD3R2KU.js";
|
|
107
114
|
import {
|
|
108
|
-
|
|
109
|
-
} from "./chunk-
|
|
115
|
+
createConsoleLogger
|
|
116
|
+
} from "./chunk-MDW7ZR7V.js";
|
|
110
117
|
import {
|
|
111
|
-
createConsoleLogger,
|
|
112
118
|
loggers,
|
|
113
119
|
pinDimension,
|
|
114
120
|
withSpan,
|
|
115
121
|
withTraceContext
|
|
116
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-KCQDXIJU.js";
|
|
117
123
|
import {
|
|
118
124
|
StepCache
|
|
119
125
|
} from "./chunk-BQJIFRAZ.js";
|
|
@@ -122,16 +128,15 @@ import {
|
|
|
122
128
|
InvalidCurrencyError,
|
|
123
129
|
UnsupportedCurrencyError,
|
|
124
130
|
createFxFetcher,
|
|
125
|
-
fxRateFor,
|
|
126
|
-
resolveFxSourceFromEnv,
|
|
127
|
-
validateCurrency
|
|
128
|
-
} from "./chunk-BYCEKO65.js";
|
|
129
|
-
import {
|
|
130
131
|
fiatToSatsCeil,
|
|
132
|
+
fxRateFor,
|
|
131
133
|
parseUsdPrice,
|
|
134
|
+
readFxSourceFailure,
|
|
135
|
+
resolveFxSourceFromEnv,
|
|
132
136
|
roundUsd,
|
|
133
|
-
satsToFiat
|
|
134
|
-
|
|
137
|
+
satsToFiat,
|
|
138
|
+
validateCurrency
|
|
139
|
+
} from "./chunk-HPCXF3DV.js";
|
|
135
140
|
import {
|
|
136
141
|
CreditLedger,
|
|
137
142
|
CreditLedgerError,
|
|
@@ -147,30 +152,26 @@ import {
|
|
|
147
152
|
isNonChannelBitcoinRail,
|
|
148
153
|
netOwedSats,
|
|
149
154
|
x402SettlementPending
|
|
150
|
-
} from "./chunk-
|
|
151
|
-
import {
|
|
152
|
-
withSdkInitLock
|
|
153
|
-
} from "./chunk-COYKJRMM.js";
|
|
155
|
+
} from "./chunk-IRXIH775.js";
|
|
154
156
|
import {
|
|
155
157
|
withPostgresRecoveryContext
|
|
156
|
-
} from "./chunk-
|
|
158
|
+
} from "./chunk-NV7Z7377.js";
|
|
157
159
|
import {
|
|
160
|
+
DvmError,
|
|
158
161
|
x402NetworkByCaip2
|
|
159
|
-
} from "./chunk-
|
|
160
|
-
import {
|
|
161
|
-
TEMPO_MODERATO_CHAIN_ID,
|
|
162
|
-
TEMPO_MODERATO_RPC,
|
|
163
|
-
advertisedMethods,
|
|
164
|
-
challengeMeta,
|
|
165
|
-
installHostedTempoChargeGuard,
|
|
166
|
-
installHostedTempoCloseGuard,
|
|
167
|
-
isTempoInsufficientFundsError,
|
|
168
|
-
resolveTempoNetwork
|
|
169
|
-
} from "./chunk-IXR5RFK7.js";
|
|
162
|
+
} from "./chunk-BPYMEMQX.js";
|
|
170
163
|
import {
|
|
171
164
|
createDiagnosticCapabilityAuthority,
|
|
172
165
|
diagnosticConsole
|
|
173
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-ZCNPIILZ.js";
|
|
167
|
+
import {
|
|
168
|
+
MemoryProcessedPaymentStore,
|
|
169
|
+
PostgresProcessedPaymentStore,
|
|
170
|
+
ProcessedPaymentReplayError
|
|
171
|
+
} from "./chunk-XRLKGCAW.js";
|
|
172
|
+
import {
|
|
173
|
+
withSdkInitLock
|
|
174
|
+
} from "./chunk-COYKJRMM.js";
|
|
174
175
|
|
|
175
176
|
// src/sdk/server/lock-pubkey-store.ts
|
|
176
177
|
async function initLockPubkeyTable(db) {
|
|
@@ -1073,7 +1074,8 @@ async function resolveFxSnapshot(fetcher) {
|
|
|
1073
1074
|
return {
|
|
1074
1075
|
ok: false,
|
|
1075
1076
|
reason: "rate_stale_refused",
|
|
1076
|
-
detail: `snapshot ${err.knownStale.staleDays.toString()}d stale
|
|
1077
|
+
detail: `snapshot ${err.knownStale.staleDays.toString()}d stale`,
|
|
1078
|
+
sourceFailure: readFxSourceFailure(err)
|
|
1077
1079
|
};
|
|
1078
1080
|
}
|
|
1079
1081
|
const cached = fetcher.lastKnown?.();
|
|
@@ -1083,7 +1085,8 @@ async function resolveFxSnapshot(fetcher) {
|
|
|
1083
1085
|
return {
|
|
1084
1086
|
ok: false,
|
|
1085
1087
|
reason: "rate_unavailable",
|
|
1086
|
-
detail: err instanceof Error ? err.message : String(err)
|
|
1088
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
1089
|
+
sourceFailure: err instanceof FxRateUnavailableError ? readFxSourceFailure(err) ?? { category: "unknown" } : { category: "unknown" }
|
|
1087
1090
|
};
|
|
1088
1091
|
}
|
|
1089
1092
|
}
|
|
@@ -1110,7 +1113,10 @@ async function msatsToFiatMicro(args) {
|
|
|
1110
1113
|
// A currency the snapshot never carried is the rate source narrowing, not
|
|
1111
1114
|
// a currency this DVM doesn't speak — `fxRateFor` separates the two.
|
|
1112
1115
|
reason: err instanceof FxRateUnavailableError ? "rate_unavailable" : "unsupported_currency",
|
|
1113
|
-
detail: err instanceof Error ? err.message : String(err)
|
|
1116
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
1117
|
+
...err instanceof FxRateUnavailableError && {
|
|
1118
|
+
sourceFailure: readFxSourceFailure(err) ?? { category: "unknown" }
|
|
1119
|
+
}
|
|
1114
1120
|
};
|
|
1115
1121
|
}
|
|
1116
1122
|
const amountMicro = Math.round(amount * 1e6);
|
|
@@ -1975,9 +1981,10 @@ async function createX402BatchSettlementServer(opts) {
|
|
|
1975
1981
|
throw new Error("x402 batch-settlement payTo must be a 20-byte EVM address");
|
|
1976
1982
|
}
|
|
1977
1983
|
const withdrawDelay = opts.config.withdrawDelay ?? X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS;
|
|
1978
|
-
|
|
1984
|
+
const minimumWithdrawDelay = opts.network === X402_BATCH_SETTLEMENT_NETWORK ? 900 : X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS;
|
|
1985
|
+
if (!Number.isInteger(withdrawDelay) || withdrawDelay < minimumWithdrawDelay) {
|
|
1979
1986
|
throw new Error(
|
|
1980
|
-
`x402 batch-settlement withdrawDelay must be at least ${String(
|
|
1987
|
+
`x402 batch-settlement withdrawDelay must be at least ${String(minimumWithdrawDelay)} seconds`
|
|
1981
1988
|
);
|
|
1982
1989
|
}
|
|
1983
1990
|
if (opts.config.autoSettlement !== false && opts.config.autoSettlement?.selectRefundChannels) {
|
|
@@ -2078,6 +2085,7 @@ async function createX402BatchSettlementServer(opts) {
|
|
|
2078
2085
|
payTo: opts.payTo,
|
|
2079
2086
|
network: opts.network,
|
|
2080
2087
|
storage,
|
|
2088
|
+
earnedNative: opts.earnedNative,
|
|
2081
2089
|
settleIntervalMs: (settlementConfig.settleIntervalSecs ?? X402_BATCH_AUTO_SETTLEMENT.settleIntervalSecs ?? 300) * 1e3,
|
|
2082
2090
|
...postgres ? { listWedgedRefunds: () => listWedgedRefunds(postgres) } : {}
|
|
2083
2091
|
});
|
|
@@ -2832,22 +2840,19 @@ function claimCeilingSelector(earnedNative) {
|
|
|
2832
2840
|
const charged = BigInt(channel.chargedCumulativeAmount);
|
|
2833
2841
|
const claimed = BigInt(channel.totalClaimed);
|
|
2834
2842
|
if (charged <= claimed) continue;
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
earned = await earnedNative(channel.channelId.toLowerCase());
|
|
2838
|
-
} catch (error) {
|
|
2843
|
+
const resolved = await x402EarnedCeiling(channel, earnedNative);
|
|
2844
|
+
if (resolved.kind === "unresolved") {
|
|
2839
2845
|
loggers.x402.warn("x402_claim_ceiling_unresolved", {
|
|
2840
2846
|
"channel.id": channel.channelId,
|
|
2841
|
-
error: error instanceof Error ? error.message : String(error)
|
|
2847
|
+
error: resolved.error instanceof Error ? resolved.error.message : String(resolved.error)
|
|
2842
2848
|
});
|
|
2843
2849
|
continue;
|
|
2844
2850
|
}
|
|
2845
|
-
if (
|
|
2851
|
+
if (resolved.kind === "unbound") {
|
|
2846
2852
|
loggers.x402.warn("x402_claim_ceiling_unbound", { "channel.id": channel.channelId });
|
|
2847
2853
|
continue;
|
|
2848
2854
|
}
|
|
2849
|
-
const
|
|
2850
|
-
const ceiling = wanted < charged ? wanted : charged;
|
|
2855
|
+
const { ceiling } = resolved;
|
|
2851
2856
|
if (ceiling <= claimed) continue;
|
|
2852
2857
|
selected.push({ ...channel, chargedCumulativeAmount: ceiling.toString() });
|
|
2853
2858
|
}
|
|
@@ -3115,6 +3120,10 @@ function decodeBatchPayment(header) {
|
|
|
3115
3120
|
if (!isBatchSettlementDepositPayload2(parsed.payload) && !isBatchSettlementVoucherPayload(parsed.payload) && !isBatchSettlementRefundPayload2(parsed.payload)) {
|
|
3116
3121
|
throw new Error("invalid batch-settlement payload");
|
|
3117
3122
|
}
|
|
3123
|
+
const voucher = parsed.payload.voucher;
|
|
3124
|
+
if (typeof voucher.channelId !== "string" || typeof voucher.maxClaimableAmount !== "string" || typeof voucher.signature !== "string") {
|
|
3125
|
+
throw new Error("invalid batch-settlement voucher");
|
|
3126
|
+
}
|
|
3118
3127
|
return parsed;
|
|
3119
3128
|
}
|
|
3120
3129
|
function batchVoucher(payload) {
|
|
@@ -3163,10 +3172,66 @@ function isRecord(value) {
|
|
|
3163
3172
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
3164
3173
|
}
|
|
3165
3174
|
|
|
3175
|
+
// src/sdk/server/payment-diagnostics.ts
|
|
3176
|
+
import { Errors } from "mppx";
|
|
3177
|
+
function paymentFailureFields(error) {
|
|
3178
|
+
let category = "unknown";
|
|
3179
|
+
try {
|
|
3180
|
+
if (error instanceof ProcessedPaymentReplayError) category = "replay_detected";
|
|
3181
|
+
else if (error instanceof CreditLedgerError) category = "ledger_refused";
|
|
3182
|
+
else if (error instanceof Errors.InvalidChallengeError) category = "invalid_challenge";
|
|
3183
|
+
else if (error instanceof Errors.MalformedCredentialError || error instanceof Errors.InvalidPayloadError) category = "malformed_credential";
|
|
3184
|
+
else if (error instanceof Errors.PaymentExpiredError) category = "payment_expired";
|
|
3185
|
+
else if (error instanceof Errors.VerificationFailedError) category = "verification_failed";
|
|
3186
|
+
else if (error instanceof Errors.PaymentInsufficientError || error instanceof Errors.InsufficientBalanceError) category = "insufficient_funds";
|
|
3187
|
+
else if (error instanceof Errors.InvalidSignatureError) category = "invalid_signature";
|
|
3188
|
+
else if (error instanceof Errors.PaymentMethodUnsupportedError) category = "unsupported_method";
|
|
3189
|
+
} catch {
|
|
3190
|
+
}
|
|
3191
|
+
return { failure_category: category, failure_stage: paymentFailureStage(error) };
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3166
3194
|
// src/sdk/server/payment.ts
|
|
3167
|
-
import { randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
3195
|
+
import { createHash as createHash4, randomBytes, randomUUID as randomUUID2 } from "crypto";
|
|
3168
3196
|
import { Challenge } from "mppx";
|
|
3169
3197
|
|
|
3198
|
+
// src/lib/cashu/verify.ts
|
|
3199
|
+
import { getTokenMetadata } from "@cashu/cashu-ts";
|
|
3200
|
+
function verifyCashuToken(token, acceptedMints) {
|
|
3201
|
+
let mint, unit, totalMsats;
|
|
3202
|
+
try {
|
|
3203
|
+
const meta = getTokenMetadata(token);
|
|
3204
|
+
mint = meta.mint;
|
|
3205
|
+
unit = meta.unit;
|
|
3206
|
+
totalMsats = meta.amount.toNumber() * 1e3;
|
|
3207
|
+
} catch {
|
|
3208
|
+
throw new DvmError(
|
|
3209
|
+
"cashu_invalid_token",
|
|
3210
|
+
"The Cashu token could not be decoded.",
|
|
3211
|
+
"Ensure the token is a valid cashuA... or cashuB... string."
|
|
3212
|
+
);
|
|
3213
|
+
}
|
|
3214
|
+
const normalised = acceptedMints.map(normaliseMintUrl);
|
|
3215
|
+
if (!normalised.includes(normaliseMintUrl(mint))) {
|
|
3216
|
+
throw new DvmError(
|
|
3217
|
+
"cashu_mint_not_accepted",
|
|
3218
|
+
`Mint ${mint} is not accepted by this provider.`,
|
|
3219
|
+
`Accepted mints: ${acceptedMints.join(", ")}`
|
|
3220
|
+
);
|
|
3221
|
+
}
|
|
3222
|
+
return { mint, totalMsats, unit };
|
|
3223
|
+
}
|
|
3224
|
+
function normaliseMintUrl(url) {
|
|
3225
|
+
try {
|
|
3226
|
+
const u = new URL(url);
|
|
3227
|
+
u.hostname = u.hostname.toLowerCase();
|
|
3228
|
+
u.pathname = u.pathname.replace(/\/+/g, "/").replace(/\/+$/, "") || "/";
|
|
3229
|
+
return u.toString().replace(/\/$/, "");
|
|
3230
|
+
} catch {
|
|
3231
|
+
return url.toLowerCase().replace(/\/+$/, "");
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3170
3235
|
// src/sdk/server/mpp-units.ts
|
|
3171
3236
|
function decimalsFor(methodName) {
|
|
3172
3237
|
switch (methodName) {
|
|
@@ -3221,6 +3286,22 @@ function methodNativeAmountToDecimal(amount, methodName) {
|
|
|
3221
3286
|
return `${nativeAmount2 / scale}.${(nativeAmount2 % scale).toString().padStart(decimals, "0")}`;
|
|
3222
3287
|
}
|
|
3223
3288
|
|
|
3289
|
+
// src/lib/mints.ts
|
|
3290
|
+
function isTestMintUrl(url) {
|
|
3291
|
+
let host;
|
|
3292
|
+
try {
|
|
3293
|
+
host = new URL(url).hostname.toLowerCase();
|
|
3294
|
+
} catch {
|
|
3295
|
+
return false;
|
|
3296
|
+
}
|
|
3297
|
+
if (host.startsWith("[") && host.endsWith("]")) host = host.slice(1, -1);
|
|
3298
|
+
if (LOOPBACK_HOSTS.has(host)) return true;
|
|
3299
|
+
if (host.endsWith(".localhost")) return true;
|
|
3300
|
+
return TEST_MINT_HOSTS.has(host);
|
|
3301
|
+
}
|
|
3302
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1"]);
|
|
3303
|
+
var TEST_MINT_HOSTS = /* @__PURE__ */ new Set(["testnut.cashu.space", "dvmkit-testmint.fly.dev"]);
|
|
3304
|
+
|
|
3224
3305
|
// src/sdk/server/wallet-accumulator-receive.ts
|
|
3225
3306
|
import {
|
|
3226
3307
|
Amount as Amount2,
|
|
@@ -3470,6 +3551,9 @@ async function issueUpfrontChallenges(mpp, requiredMsats, resourcePath, btcUsdRa
|
|
|
3470
3551
|
);
|
|
3471
3552
|
}
|
|
3472
3553
|
async function verifyUpfrontPayment(opts) {
|
|
3554
|
+
return withPaymentDiagnostics(() => verifyUpfrontPaymentInScope(opts));
|
|
3555
|
+
}
|
|
3556
|
+
async function verifyUpfrontPaymentInScope(opts) {
|
|
3473
3557
|
const {
|
|
3474
3558
|
cashuToken,
|
|
3475
3559
|
requiredMsats,
|
|
@@ -3735,7 +3819,10 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3735
3819
|
);
|
|
3736
3820
|
} catch (err) {
|
|
3737
3821
|
const mapped = mapLedgerCommitError(err, x402Requirements);
|
|
3738
|
-
if (mapped)
|
|
3822
|
+
if (mapped) {
|
|
3823
|
+
logCredentialRejected("x402", "upfront", err);
|
|
3824
|
+
return mapped;
|
|
3825
|
+
}
|
|
3739
3826
|
logCredentialRejected("x402", "upfront", err);
|
|
3740
3827
|
return {
|
|
3741
3828
|
paidMsats: 0,
|
|
@@ -3796,15 +3883,15 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3796
3883
|
x402Requirements
|
|
3797
3884
|
});
|
|
3798
3885
|
}
|
|
3799
|
-
const { verifyX402Payment } = await import("./x402-
|
|
3800
|
-
const receipt = await verifyX402Payment(
|
|
3886
|
+
const { verifyX402Payment } = await import("./x402-3IQ3HXSG.js");
|
|
3887
|
+
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
3801
3888
|
x402Payment,
|
|
3802
3889
|
x402Config,
|
|
3803
3890
|
requiredUsdcMicro,
|
|
3804
3891
|
x402Resource ?? "/v1/job",
|
|
3805
3892
|
rate ?? 0,
|
|
3806
3893
|
x402ExactVersions
|
|
3807
|
-
);
|
|
3894
|
+
));
|
|
3808
3895
|
if (receipt.verified) {
|
|
3809
3896
|
const settledUsdcMicro = receipt.amountUsdcMicro;
|
|
3810
3897
|
const paidMsats = settledUsdcMicro === void 0 ? receipt.amountMsats : x402SettledShare(requiredMsats, Number(requiredUsdcMicro), settledUsdcMicro);
|
|
@@ -3848,7 +3935,10 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3848
3935
|
});
|
|
3849
3936
|
} catch (err) {
|
|
3850
3937
|
const mapped = mapLedgerCommitError(err, x402Requirements, true);
|
|
3851
|
-
if (mapped)
|
|
3938
|
+
if (mapped) {
|
|
3939
|
+
logCredentialRejected("x402", "upfront", err);
|
|
3940
|
+
return mapped;
|
|
3941
|
+
}
|
|
3852
3942
|
throw err;
|
|
3853
3943
|
}
|
|
3854
3944
|
}
|
|
@@ -3956,6 +4046,30 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3956
4046
|
}
|
|
3957
4047
|
const expectedAmount = opts.priceFiat?.currency === "usd" ? fiatMicroToMethodAmount(opts.priceFiat.amountMicro, cred.challenge.method) : msatsToMethodAmount(requiredMsats, cred.challenge.method, rate);
|
|
3958
4048
|
const sessionBasis = mppSessionBasis(cred);
|
|
4049
|
+
const replayRealm = mpp.realm ?? cred.challenge.realm;
|
|
4050
|
+
if (consumedCredentialStore && await withPaymentStage("replay_store", () => consumedCredentialStore.has(replayRealm, cred.challenge.id))) {
|
|
4051
|
+
const mppChallenges = await issueUpfrontChallenges(
|
|
4052
|
+
mpp,
|
|
4053
|
+
requiredMsats,
|
|
4054
|
+
resourcePath ?? "/v1/job",
|
|
4055
|
+
rate,
|
|
4056
|
+
sessionIssuable,
|
|
4057
|
+
opts.fundOnly?.allowOneShotStablecoin,
|
|
4058
|
+
opts.priceFiat
|
|
4059
|
+
);
|
|
4060
|
+
return {
|
|
4061
|
+
paidMsats: 0,
|
|
4062
|
+
receivedProofs: [],
|
|
4063
|
+
error: {
|
|
4064
|
+
body: paymentErrorBody("payment_invalid", {
|
|
4065
|
+
message: "MPP credential already used"
|
|
4066
|
+
}),
|
|
4067
|
+
status: 402,
|
|
4068
|
+
mppChallenges,
|
|
4069
|
+
...x402Requirements && { x402Requirements }
|
|
4070
|
+
}
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
3959
4073
|
let tempoReceipt;
|
|
3960
4074
|
const broadcast = async () => {
|
|
3961
4075
|
const receipt = await loggers.tempo.span(
|
|
@@ -3965,7 +4079,7 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3965
4079
|
challenge_id: cred.challenge.id,
|
|
3966
4080
|
amount: expectedAmount
|
|
3967
4081
|
},
|
|
3968
|
-
() => mpp.broadcastCredential(mppCredential, {
|
|
4082
|
+
() => withPaymentStage("verifier_broadcast", () => mpp.broadcastCredential(mppCredential, {
|
|
3969
4083
|
request: { amount: expectedAmount },
|
|
3970
4084
|
...opts.hostingAdmissionId && {
|
|
3971
4085
|
hostedPaymentIntent: {
|
|
@@ -3984,7 +4098,8 @@ async function verifyUpfrontPayment(opts) {
|
|
|
3984
4098
|
path: resourcePath ?? "/v1/job",
|
|
3985
4099
|
nonce: challengeMeta(cred.challenge)?.nonce ?? ""
|
|
3986
4100
|
}
|
|
3987
|
-
})
|
|
4101
|
+
})),
|
|
4102
|
+
{ onError: paymentFailureFields }
|
|
3988
4103
|
);
|
|
3989
4104
|
tempoReceipt = receipt;
|
|
3990
4105
|
return receipt;
|
|
@@ -4041,7 +4156,10 @@ async function verifyUpfrontPayment(opts) {
|
|
|
4041
4156
|
credited = accepted.result;
|
|
4042
4157
|
} catch (err) {
|
|
4043
4158
|
const mapped = mapLedgerCommitError(err, x402Requirements, true);
|
|
4044
|
-
if (mapped)
|
|
4159
|
+
if (mapped) {
|
|
4160
|
+
logCredentialRejected("tempo", "upfront", err);
|
|
4161
|
+
return mapped;
|
|
4162
|
+
}
|
|
4045
4163
|
throw err;
|
|
4046
4164
|
}
|
|
4047
4165
|
} else {
|
|
@@ -4069,35 +4187,12 @@ async function verifyUpfrontPayment(opts) {
|
|
|
4069
4187
|
}
|
|
4070
4188
|
};
|
|
4071
4189
|
}
|
|
4072
|
-
if (consumedCredentialStore) {
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
requiredMsats,
|
|
4079
|
-
resourcePath ?? "/v1/job",
|
|
4080
|
-
rate,
|
|
4081
|
-
sessionIssuable,
|
|
4082
|
-
opts.fundOnly?.allowOneShotStablecoin,
|
|
4083
|
-
opts.priceFiat
|
|
4084
|
-
);
|
|
4085
|
-
return {
|
|
4086
|
-
paidMsats: 0,
|
|
4087
|
-
receivedProofs: [],
|
|
4088
|
-
error: {
|
|
4089
|
-
body: paymentErrorBody("payment_invalid", {
|
|
4090
|
-
message: "MPP credential already used"
|
|
4091
|
-
}),
|
|
4092
|
-
status: 402,
|
|
4093
|
-
mppChallenges,
|
|
4094
|
-
...x402Requirements && { x402Requirements }
|
|
4095
|
-
}
|
|
4096
|
-
};
|
|
4097
|
-
}
|
|
4098
|
-
if (!sessionBasis) {
|
|
4099
|
-
await consumedCredentialStore.mark(realm, id, CONSUMED_CREDENTIAL_TTL_MS / 1e3);
|
|
4100
|
-
}
|
|
4190
|
+
if (consumedCredentialStore && !sessionBasis) {
|
|
4191
|
+
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(
|
|
4192
|
+
replayRealm,
|
|
4193
|
+
cred.challenge.id,
|
|
4194
|
+
CONSUMED_CREDENTIAL_TTL_MS / 1e3
|
|
4195
|
+
));
|
|
4101
4196
|
}
|
|
4102
4197
|
if (ledgerCtx) {
|
|
4103
4198
|
try {
|
|
@@ -4111,16 +4206,27 @@ async function verifyUpfrontPayment(opts) {
|
|
|
4111
4206
|
});
|
|
4112
4207
|
} catch (err) {
|
|
4113
4208
|
const mapped = mapLedgerCommitError(err, x402Requirements, true);
|
|
4114
|
-
if (mapped)
|
|
4209
|
+
if (mapped) {
|
|
4210
|
+
logCredentialRejected("tempo", "upfront", err);
|
|
4211
|
+
return mapped;
|
|
4212
|
+
}
|
|
4115
4213
|
throw err;
|
|
4116
4214
|
}
|
|
4117
4215
|
}
|
|
4118
4216
|
if (sessionBasis && consumedCredentialStore) {
|
|
4119
|
-
await consumedCredentialStore.mark(
|
|
4120
|
-
|
|
4217
|
+
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(
|
|
4218
|
+
replayRealm,
|
|
4121
4219
|
cred.challenge.id,
|
|
4122
4220
|
CONSUMED_CREDENTIAL_TTL_MS / 1e3
|
|
4123
|
-
)
|
|
4221
|
+
)).catch((error) => {
|
|
4222
|
+
diagnosticConsole.warn({
|
|
4223
|
+
level: "warn",
|
|
4224
|
+
event: "tempo_replay_mark_failed",
|
|
4225
|
+
phase: "upfront",
|
|
4226
|
+
rail: "tempo",
|
|
4227
|
+
...paymentFailureFields(error)
|
|
4228
|
+
});
|
|
4229
|
+
});
|
|
4124
4230
|
}
|
|
4125
4231
|
if (credited) {
|
|
4126
4232
|
await mpp.completeHostedTempoCharge?.(cred.challenge.id).catch((error) => {
|
|
@@ -4329,6 +4435,22 @@ async function verifyTempoSessionManagementCredential(args) {
|
|
|
4329
4435
|
throw new Error("Hosted Tempo close requires non-mutating credential validation");
|
|
4330
4436
|
}
|
|
4331
4437
|
await args.mpp.validateCredential(credential, verifyOptions);
|
|
4438
|
+
if (args.action === "close") {
|
|
4439
|
+
if (!args.mpp.assertTempoSessionCloseVoucher) {
|
|
4440
|
+
throw new Error("Hosted Tempo close requires stored-channel voucher validation");
|
|
4441
|
+
}
|
|
4442
|
+
const { cumulativeAmount, signature } = credential.payload;
|
|
4443
|
+
if (typeof cumulativeAmount !== "string" || typeof signature !== "string") {
|
|
4444
|
+
throw new Error("Expected a Tempo session close voucher");
|
|
4445
|
+
}
|
|
4446
|
+
await args.mpp.assertTempoSessionCloseVoucher({
|
|
4447
|
+
channelId: payload.channelId,
|
|
4448
|
+
cumulativeAmount: BigInt(cumulativeAmount),
|
|
4449
|
+
signature,
|
|
4450
|
+
descriptor: credential.payload.descriptor,
|
|
4451
|
+
request: credential.challenge.request
|
|
4452
|
+
});
|
|
4453
|
+
}
|
|
4332
4454
|
}
|
|
4333
4455
|
await args.onBound?.();
|
|
4334
4456
|
const receipt = await args.mpp.broadcastCredential(credential, verifyOptions);
|
|
@@ -4689,6 +4811,9 @@ function buildPaymentErrorResponse(body, challenges, x402Requirements, status, x
|
|
|
4689
4811
|
return new Response(JSON.stringify(mergedBody), { status: status ?? 402, headers });
|
|
4690
4812
|
}
|
|
4691
4813
|
async function verifyIncomingPayment(body, opts, snapshot) {
|
|
4814
|
+
return withPaymentDiagnostics(() => verifyIncomingPaymentInScope(body, opts, snapshot));
|
|
4815
|
+
}
|
|
4816
|
+
async function verifyIncomingPaymentInScope(body, opts, snapshot) {
|
|
4692
4817
|
if (body.type !== "payment") return {};
|
|
4693
4818
|
if (body.content.cashu_token) {
|
|
4694
4819
|
if (opts.cashuMode === "p2pk-accumulator" && (opts.accumulatorDb || opts.disposableCashu) && opts.dvmId && opts.lockPubkeys && opts.lockPubkeys.length > 0) {
|
|
@@ -4771,15 +4896,15 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4771
4896
|
snapshot
|
|
4772
4897
|
});
|
|
4773
4898
|
}
|
|
4774
|
-
const { verifyX402Payment } = await import("./x402-
|
|
4775
|
-
const receipt = await verifyX402Payment(
|
|
4899
|
+
const { verifyX402Payment } = await import("./x402-3IQ3HXSG.js");
|
|
4900
|
+
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
4776
4901
|
body.content.x402_payment,
|
|
4777
4902
|
opts.x402Config,
|
|
4778
4903
|
requiredUsdcMicro,
|
|
4779
4904
|
opts.resourcePath ?? "/v1/job",
|
|
4780
4905
|
rate,
|
|
4781
4906
|
opts.x402ExactVersions
|
|
4782
|
-
);
|
|
4907
|
+
));
|
|
4783
4908
|
if (!receipt.verified) {
|
|
4784
4909
|
return {
|
|
4785
4910
|
error: {
|
|
@@ -4828,6 +4953,7 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4828
4953
|
} catch (err) {
|
|
4829
4954
|
const mapped = mapLedgerCommitError(err, void 0, true);
|
|
4830
4955
|
if (mapped?.error) {
|
|
4956
|
+
logCredentialRejected("x402", "mid-job", err);
|
|
4831
4957
|
return { error: { body: mapped.error.body, status: mapped.error.status } };
|
|
4832
4958
|
}
|
|
4833
4959
|
throw err;
|
|
@@ -4935,13 +5061,14 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4935
5061
|
challenge_id: credential.challenge.id,
|
|
4936
5062
|
amount: expectedAmount
|
|
4937
5063
|
},
|
|
4938
|
-
() => mppServer.broadcastCredential(credential, {
|
|
5064
|
+
() => withPaymentStage("verifier_broadcast", () => mppServer.broadcastCredential(credential, {
|
|
4939
5065
|
request: { amount: expectedAmount },
|
|
4940
5066
|
...opts.hostingPaymentSeq !== void 0 && {
|
|
4941
5067
|
hostedPaymentIntent: { jobId: opts.jobId, paymentSeq: opts.hostingPaymentSeq }
|
|
4942
5068
|
},
|
|
4943
5069
|
...expectedMeta && { meta: expectedMeta }
|
|
4944
|
-
})
|
|
5070
|
+
})),
|
|
5071
|
+
{ onError: paymentFailureFields }
|
|
4945
5072
|
);
|
|
4946
5073
|
let credited;
|
|
4947
5074
|
if (ledgerCtx) {
|
|
@@ -4950,6 +5077,7 @@ async function verifyIncomingPayment(body, opts, snapshot) {
|
|
|
4950
5077
|
} catch (err) {
|
|
4951
5078
|
const mapped = mapLedgerCommitError(err, void 0, true);
|
|
4952
5079
|
if (mapped?.error) {
|
|
5080
|
+
logCredentialRejected("tempo", "mid-job", err);
|
|
4953
5081
|
return { error: { body: mapped.error.body, status: mapped.error.status } };
|
|
4954
5082
|
}
|
|
4955
5083
|
throw err;
|
|
@@ -5144,6 +5272,9 @@ function applyPaymentInfoToJob(job, info) {
|
|
|
5144
5272
|
creditPendingPayment(job);
|
|
5145
5273
|
}
|
|
5146
5274
|
async function processIncomingPayment(job, body, opts) {
|
|
5275
|
+
return withPaymentDiagnostics(() => processIncomingPaymentInScope(job, body, opts));
|
|
5276
|
+
}
|
|
5277
|
+
async function processIncomingPaymentInScope(job, body, opts) {
|
|
5147
5278
|
if (body.type !== "payment") return null;
|
|
5148
5279
|
if (body.content.cashu_token) {
|
|
5149
5280
|
if (opts.cashuMode === "p2pk-accumulator" && (opts.accumulatorDb || opts.disposableCashu) && opts.dvmId && opts.lockPubkeys && opts.lockPubkeys.length > 0) {
|
|
@@ -5196,15 +5327,15 @@ async function processIncomingPayment(job, body, opts) {
|
|
|
5196
5327
|
try {
|
|
5197
5328
|
const requiredMsats = job.pendingPaymentMsats ?? 0;
|
|
5198
5329
|
const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
|
|
5199
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5200
|
-
const receipt = await verifyX402Payment(
|
|
5330
|
+
const { verifyX402Payment } = await import("./x402-3IQ3HXSG.js");
|
|
5331
|
+
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5201
5332
|
body.content.x402_payment,
|
|
5202
5333
|
opts.x402Config,
|
|
5203
5334
|
requiredUsdcMicro,
|
|
5204
5335
|
opts.resourcePath ?? "/v1/job",
|
|
5205
5336
|
rate,
|
|
5206
5337
|
opts.x402ExactVersions
|
|
5207
|
-
);
|
|
5338
|
+
));
|
|
5208
5339
|
if (receipt.verified) {
|
|
5209
5340
|
if (job.pendingX402Nonce !== void 0) {
|
|
5210
5341
|
const incomingNonce = decodePayment(body.content.x402_payment).payload.authorization.nonce;
|
|
@@ -5271,13 +5402,14 @@ async function processIncomingPayment(job, body, opts) {
|
|
|
5271
5402
|
challenge_id: credential.challenge.id,
|
|
5272
5403
|
amount: expectedAmount
|
|
5273
5404
|
},
|
|
5274
|
-
() => mppHandle.broadcastCredential(credential, {
|
|
5405
|
+
() => withPaymentStage("verifier_broadcast", () => mppHandle.broadcastCredential(credential, {
|
|
5275
5406
|
request: { amount: expectedAmount },
|
|
5276
5407
|
...opts.hostingPaymentSeq !== void 0 && {
|
|
5277
5408
|
hostedPaymentIntent: { jobId: opts.jobId, paymentSeq: opts.hostingPaymentSeq }
|
|
5278
5409
|
},
|
|
5279
5410
|
...expectedMeta && { meta: expectedMeta }
|
|
5280
|
-
})
|
|
5411
|
+
})),
|
|
5412
|
+
{ onError: paymentFailureFields }
|
|
5281
5413
|
);
|
|
5282
5414
|
if (!job.pendingMppChallengeIds?.includes(credential.challenge.id)) {
|
|
5283
5415
|
return {
|
|
@@ -5583,7 +5715,10 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
|
|
|
5583
5715
|
job_id: opts.jobId,
|
|
5584
5716
|
credit_id: snapshot.creditId,
|
|
5585
5717
|
draw_id: snapshot.drawId,
|
|
5586
|
-
...extra
|
|
5718
|
+
...extra,
|
|
5719
|
+
...typeof opts.jobId === "string" && {
|
|
5720
|
+
job_id_hash: createHash4("sha256").update(opts.jobId, "utf8").digest("hex")
|
|
5721
|
+
}
|
|
5587
5722
|
}
|
|
5588
5723
|
);
|
|
5589
5724
|
};
|
|
@@ -5646,7 +5781,10 @@ async function resolveTopUpLedgerContext(opts, snapshot, binding) {
|
|
|
5646
5781
|
logSkip("denomination_unavailable", {
|
|
5647
5782
|
currency,
|
|
5648
5783
|
cause: denomination.reason,
|
|
5649
|
-
...denomination.
|
|
5784
|
+
...denomination.sourceFailure && {
|
|
5785
|
+
source_failure: denomination.sourceFailure.category,
|
|
5786
|
+
source_status: denomination.sourceFailure.httpStatus
|
|
5787
|
+
}
|
|
5650
5788
|
});
|
|
5651
5789
|
return void 0;
|
|
5652
5790
|
}
|
|
@@ -5795,6 +5933,9 @@ function withDrawBasis(info, ctx, committed) {
|
|
|
5795
5933
|
};
|
|
5796
5934
|
}
|
|
5797
5935
|
async function fundAndDraw(ctx, funding, tx) {
|
|
5936
|
+
return withPaymentStage("funding_ledger", () => fundAndDrawInScope(ctx, funding, tx));
|
|
5937
|
+
}
|
|
5938
|
+
async function fundAndDrawInScope(ctx, funding, tx) {
|
|
5798
5939
|
const env = ctx.creditEnvelope;
|
|
5799
5940
|
const fundedMicro = funding.fundedMicro ?? fundedMicroFor(ctx.priceFiat, funding.paidMsats, ctx.requiredMsats);
|
|
5800
5941
|
const shortMidJob = ctx.midJob === true && funding.paidMsats < ctx.requiredMsats;
|
|
@@ -5833,9 +5974,11 @@ async function fundAndDraw(ctx, funding, tx) {
|
|
|
5833
5974
|
throw new Error("deposit outbox enqueue requires the rail's open transaction and a DVM id");
|
|
5834
5975
|
}
|
|
5835
5976
|
const commitDeposit = async (result, credit) => {
|
|
5977
|
+
const instrument = credit.rail ? storedCreditBinding(credit).instrument : void 0;
|
|
5836
5978
|
const report = {
|
|
5837
5979
|
...deposit,
|
|
5838
|
-
callerPubkey: credit.callerPubkey
|
|
5980
|
+
callerPubkey: credit.callerPubkey,
|
|
5981
|
+
...instrument && { instrument }
|
|
5839
5982
|
};
|
|
5840
5983
|
if (createsDepositLiability && enqueue && tx) {
|
|
5841
5984
|
await enqueue(tx, creditDepositPayload(ctx.dvmId, report));
|
|
@@ -6017,6 +6160,7 @@ function creditDepositPayload(dvmId, funding) {
|
|
|
6017
6160
|
creditCurrency: funding.currency,
|
|
6018
6161
|
fundedAt: funding.fundedAt,
|
|
6019
6162
|
expiryMs: funding.expiryMs,
|
|
6163
|
+
...funding.instrument && { instrument: funding.instrument },
|
|
6020
6164
|
// label a session-funded deposit as one, whether or not the chain
|
|
6021
6165
|
// binding below could be read. `rail: "tempo"` alone does not say — a
|
|
6022
6166
|
// `tempo/charge` one-shot funds a credit with no channel at all — so this is
|
|
@@ -6221,7 +6365,7 @@ async function commitMarkedFunding(ctx, funding, outerTx) {
|
|
|
6221
6365
|
const env = ctx.creditEnvelope;
|
|
6222
6366
|
const creditId = ctx.fundOnly?.creditId ?? ctx.topUp?.creditId ?? env?.creditId ?? implicitCreditId(funding.rail, funding.paymentId);
|
|
6223
6367
|
const drawId = ctx.fundOnly?.fundId ?? ctx.topUp?.drawId ?? env?.drawId ?? funding.paymentId;
|
|
6224
|
-
await store.record({
|
|
6368
|
+
await withPaymentStage("replay_store", () => store.record({
|
|
6225
6369
|
dvmId: ctx.dvmId,
|
|
6226
6370
|
rail: funding.rail,
|
|
6227
6371
|
paymentId: funding.paymentId,
|
|
@@ -6229,10 +6373,10 @@ async function commitMarkedFunding(ctx, funding, outerTx) {
|
|
|
6229
6373
|
drawId,
|
|
6230
6374
|
jobId: ctx.jobId,
|
|
6231
6375
|
tx
|
|
6232
|
-
});
|
|
6376
|
+
}));
|
|
6233
6377
|
return fundAndDraw(ctx, funding, tx);
|
|
6234
6378
|
};
|
|
6235
|
-
return outerTx ? commit(outerTx) : store.withTx(commit);
|
|
6379
|
+
return outerTx ? commit(outerTx) : withPaymentStage("replay_store", () => store.withTx(commit));
|
|
6236
6380
|
}
|
|
6237
6381
|
async function commitMppFunding(ctx, credential, funding) {
|
|
6238
6382
|
const session = mppSessionBasis(credential);
|
|
@@ -6594,15 +6738,14 @@ function x402NotOfferedResult(currency) {
|
|
|
6594
6738
|
error: x402NotOfferedPaymentError(currency)
|
|
6595
6739
|
};
|
|
6596
6740
|
}
|
|
6597
|
-
function logCredentialRejected(rail, phase,
|
|
6741
|
+
function logCredentialRejected(rail, phase, err) {
|
|
6598
6742
|
diagnosticConsole.warn(
|
|
6599
6743
|
{
|
|
6600
6744
|
level: "warn",
|
|
6601
6745
|
event: `${rail}_credential_rejected`,
|
|
6602
6746
|
phase,
|
|
6603
6747
|
rail,
|
|
6604
|
-
|
|
6605
|
-
error_message: void 0
|
|
6748
|
+
...paymentFailureFields(err)
|
|
6606
6749
|
}
|
|
6607
6750
|
);
|
|
6608
6751
|
}
|
|
@@ -9060,7 +9203,7 @@ async function handle(c, opts, action) {
|
|
|
9060
9203
|
}
|
|
9061
9204
|
|
|
9062
9205
|
// src/sdk/server/x402-exact-settlement.ts
|
|
9063
|
-
import { createHash as
|
|
9206
|
+
import { createHash as createHash5 } from "crypto";
|
|
9064
9207
|
var X402ExactSettlementServer = class {
|
|
9065
9208
|
constructor(opts) {
|
|
9066
9209
|
this.opts = opts;
|
|
@@ -9386,7 +9529,7 @@ function settlementMayHaveMoved(response) {
|
|
|
9386
9529
|
return reason.includes("authorization_already_used") || reason.includes("authorization already used") || /facilitator_status_5\d\d/.test(reason);
|
|
9387
9530
|
}
|
|
9388
9531
|
function hash(parts) {
|
|
9389
|
-
return
|
|
9532
|
+
return createHash5("sha256").update(JSON.stringify(parts)).digest("hex");
|
|
9390
9533
|
}
|
|
9391
9534
|
function safeError(err) {
|
|
9392
9535
|
if (err instanceof Error) return err.name;
|
|
@@ -9560,7 +9703,7 @@ var HostingCleanupFence = class {
|
|
|
9560
9703
|
};
|
|
9561
9704
|
|
|
9562
9705
|
// src/sdk/server/hosting-settlement-report-obligations.ts
|
|
9563
|
-
import { createHash as
|
|
9706
|
+
import { createHash as createHash6, randomUUID as randomUUID3 } from "crypto";
|
|
9564
9707
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
9565
9708
|
import { BATCH_SETTLEMENT_ADDRESS as BATCH_SETTLEMENT_ADDRESS3 } from "@x402/evm";
|
|
9566
9709
|
import { computeChannelId as computeChannelId2 } from "@x402/evm/batch-settlement/client";
|
|
@@ -9623,7 +9766,7 @@ var TEMPO_CLOSED_EVENT = TempoSession.Precompile.escrowAbi.find(
|
|
|
9623
9766
|
(item) => item.type === "event" && item.name === "ChannelClosed"
|
|
9624
9767
|
);
|
|
9625
9768
|
function hash2(value) {
|
|
9626
|
-
return
|
|
9769
|
+
return createHash6("sha256").update(JSON.stringify(value)).digest("hex");
|
|
9627
9770
|
}
|
|
9628
9771
|
function hex(value, bytes) {
|
|
9629
9772
|
return typeof value === "string" && new RegExp(`^0x[0-9a-fA-F]{${bytes * 2}}$`).test(value);
|
|
@@ -9950,6 +10093,18 @@ var HostedSettlementReportObligations = class {
|
|
|
9950
10093
|
);
|
|
9951
10094
|
return result.rows[0];
|
|
9952
10095
|
}
|
|
10096
|
+
/** The original close obligation reserved for this drain, while its report is outstanding. */
|
|
10097
|
+
async pendingTempoClose(channelId, drainId) {
|
|
10098
|
+
const result = await this.pool.query(
|
|
10099
|
+
`SELECT id,tx_hash,created_at_ms FROM sdk_hosted_settlement_report_obligations
|
|
10100
|
+
WHERE dvm_id=$1 AND scope=$2 AND rail='tempo' AND operation='close' AND channel_id=$3
|
|
10101
|
+
AND original->>'drainId'=$4 AND state NOT IN ('delivered','no_report')
|
|
10102
|
+
ORDER BY created_at_ms DESC LIMIT 1`,
|
|
10103
|
+
[this.dvmId, this.scope, channelId.toLowerCase(), drainId]
|
|
10104
|
+
);
|
|
10105
|
+
const row = result.rows[0];
|
|
10106
|
+
return row && { id: row.id, txHash: row.tx_hash, reservedAtMs: Number(row.created_at_ms) };
|
|
10107
|
+
}
|
|
9953
10108
|
async submittedIds(rail, operation, txHash, batchId) {
|
|
9954
10109
|
if (!hex(txHash, 32)) throw new Error("Hosted effect has no exact transaction hash");
|
|
9955
10110
|
const result = await this.pool.query(
|
|
@@ -10089,6 +10244,10 @@ var HostedSettlementReportObligations = class {
|
|
|
10089
10244
|
}));
|
|
10090
10245
|
}
|
|
10091
10246
|
async recoverOriginalX402Refunds() {
|
|
10247
|
+
const table = await this.pool.query(
|
|
10248
|
+
"SELECT to_regclass('x402_batch_settlements') IS NOT NULL AS present"
|
|
10249
|
+
);
|
|
10250
|
+
if (!table.rows[0]?.present) return [];
|
|
10092
10251
|
const rows2 = await this.pool.query(
|
|
10093
10252
|
`SELECT obligation.id,settlement.settle_response AS response
|
|
10094
10253
|
FROM sdk_hosted_settlement_report_obligations obligation
|
|
@@ -10526,7 +10685,7 @@ var HostedSettlementReportObligations = class {
|
|
|
10526
10685
|
};
|
|
10527
10686
|
|
|
10528
10687
|
// src/sdk/server/hosting-channel-evidence.ts
|
|
10529
|
-
import { createHash as
|
|
10688
|
+
import { createHash as createHash7 } from "crypto";
|
|
10530
10689
|
import { Session as TempoSession2 } from "mppx/tempo";
|
|
10531
10690
|
import { createPublicClient as createPublicClient5, http as http5 } from "viem";
|
|
10532
10691
|
import { BATCH_SETTLEMENT_ADDRESS as BATCH_SETTLEMENT_ADDRESS4 } from "@x402/evm";
|
|
@@ -10577,7 +10736,7 @@ async function readHostedChannelSnapshot(query) {
|
|
|
10577
10736
|
};
|
|
10578
10737
|
const x402HistoryComplete = await history(names[6]);
|
|
10579
10738
|
const tempoHistoryComplete = await history(names[7]);
|
|
10580
|
-
const digest =
|
|
10739
|
+
const digest = createHash7("sha256").update(JSON.stringify({
|
|
10581
10740
|
present: [...exists].sort(),
|
|
10582
10741
|
x402,
|
|
10583
10742
|
x402Tombstones,
|
|
@@ -11659,7 +11818,8 @@ var HostingControl = class {
|
|
|
11659
11818
|
pendingAdmissionCount: Number(pending.rows[0].pending),
|
|
11660
11819
|
pendingAdmissions: inFlight.rows.map((row) => ({ admissionId: row.id, workId: row.job_id })),
|
|
11661
11820
|
unresolvedAdmissionCount: Number(pending.rows[0].unresolved),
|
|
11662
|
-
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id }))
|
|
11821
|
+
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id })),
|
|
11822
|
+
jobIdentityHeader: "v1"
|
|
11663
11823
|
};
|
|
11664
11824
|
}
|
|
11665
11825
|
};
|
|
@@ -11726,9 +11886,9 @@ import { AsyncLocalStorage } from "async_hooks";
|
|
|
11726
11886
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
11727
11887
|
|
|
11728
11888
|
// src/sdk/server/instrumented-kv.ts
|
|
11729
|
-
import { createHash as
|
|
11889
|
+
import { createHash as createHash8 } from "crypto";
|
|
11730
11890
|
function hashKey(key) {
|
|
11731
|
-
return
|
|
11891
|
+
return createHash8("sha256").update(key).digest("hex").slice(0, 16);
|
|
11732
11892
|
}
|
|
11733
11893
|
function instrumentKVStore(inner) {
|
|
11734
11894
|
return {
|
|
@@ -16504,7 +16664,7 @@ function withWallClockDeadline(promise, timeoutMs) {
|
|
|
16504
16664
|
}
|
|
16505
16665
|
|
|
16506
16666
|
// src/sdk/server/app.ts
|
|
16507
|
-
import { createHash as
|
|
16667
|
+
import { createHash as createHash10, randomBytes as randomBytes5, randomUUID as randomUUID6 } from "crypto";
|
|
16508
16668
|
import { Hono } from "hono";
|
|
16509
16669
|
import { getCookie } from "hono/cookie";
|
|
16510
16670
|
import { cors } from "hono/cors";
|
|
@@ -16526,7 +16686,7 @@ import {
|
|
|
16526
16686
|
Amount as Amount3,
|
|
16527
16687
|
CheckStateEnum as CheckStateEnum3,
|
|
16528
16688
|
getP2PKExpectedWitnessPubkeys as getP2PKExpectedWitnessPubkeys2,
|
|
16529
|
-
getTokenMetadata
|
|
16689
|
+
getTokenMetadata as getTokenMetadata2
|
|
16530
16690
|
} from "@cashu/cashu-ts";
|
|
16531
16691
|
function installAdminCreditRoutes(app, opts) {
|
|
16532
16692
|
app.get("/admin/credit/pending-drains", (c) => handlePendingDrains(c, opts));
|
|
@@ -16887,7 +17047,7 @@ async function handleParkDrain(c, opts) {
|
|
|
16887
17047
|
}
|
|
16888
17048
|
let parsed;
|
|
16889
17049
|
try {
|
|
16890
|
-
const meta =
|
|
17050
|
+
const meta = getTokenMetadata2(token);
|
|
16891
17051
|
parsed = {
|
|
16892
17052
|
mint: meta.mint,
|
|
16893
17053
|
faceSats: Amount3.from(meta.amount).toNumber(),
|
|
@@ -19293,7 +19453,7 @@ initSchemaForm();
|
|
|
19293
19453
|
}
|
|
19294
19454
|
|
|
19295
19455
|
// src/sdk/server/request-fingerprint.ts
|
|
19296
|
-
import { createHash as
|
|
19456
|
+
import { createHash as createHash9 } from "crypto";
|
|
19297
19457
|
function requestFingerprint(req, opts) {
|
|
19298
19458
|
const canonical = canonicalize({
|
|
19299
19459
|
capability: req.capability,
|
|
@@ -19301,7 +19461,7 @@ function requestFingerprint(req, opts) {
|
|
|
19301
19461
|
params: req.params ?? {},
|
|
19302
19462
|
data: opts.stripAuthEnvelope ? stripEnvelope(req.data) : req.data
|
|
19303
19463
|
});
|
|
19304
|
-
return
|
|
19464
|
+
return createHash9("sha256").update(canonical).digest("hex");
|
|
19305
19465
|
}
|
|
19306
19466
|
var ENVELOPE_KEYS = /* @__PURE__ */ new Set(["pubkey", "signature", "timestamp", "nonce", "auth_statement"]);
|
|
19307
19467
|
function stripEnvelope(data) {
|
|
@@ -19424,7 +19584,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19424
19584
|
}
|
|
19425
19585
|
}
|
|
19426
19586
|
if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
|
|
19427
|
-
const { RevenueReporter } = await import("./revenue-reporter-
|
|
19587
|
+
const { RevenueReporter } = await import("./revenue-reporter-HV7RMS54.js");
|
|
19428
19588
|
const reporter = new RevenueReporter(
|
|
19429
19589
|
opts.db,
|
|
19430
19590
|
platformUrl,
|
|
@@ -19434,7 +19594,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19434
19594
|
revenueReporter = reporter;
|
|
19435
19595
|
await reporter.init();
|
|
19436
19596
|
reporter.startRetryLoop();
|
|
19437
|
-
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-
|
|
19597
|
+
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-7P66T77I.js");
|
|
19438
19598
|
payoutReporter = new PayoutReporter({
|
|
19439
19599
|
dvmId,
|
|
19440
19600
|
db: opts.db,
|
|
@@ -19719,6 +19879,7 @@ var DVMServer = class {
|
|
|
19719
19879
|
`createDVMServer: this DVM prices in ${JSON.stringify(this.pricingCurrency)} (DVMConfig.currency) but its fx fetcher only quotes [${fxCurrencies.join(", ")}]. Wire a fetcher that carries it \u2014 createFxFetcher({ currencies: [..., ${JSON.stringify(this.pricingCurrency)}] }) \u2014 or price in one of the above.`
|
|
19720
19880
|
);
|
|
19721
19881
|
}
|
|
19882
|
+
assertCapabilityRates(descriptor.capabilities);
|
|
19722
19883
|
if (opts.mintHealthTracker) {
|
|
19723
19884
|
this.mintHealthTracker = opts.mintHealthTracker;
|
|
19724
19885
|
this.ownsMintHealthTracker = false;
|
|
@@ -20299,7 +20460,7 @@ var DVMServer = class {
|
|
|
20299
20460
|
const dvmId = this.opts.dvmId ?? `dev:${this.descriptor.name}`;
|
|
20300
20461
|
return {
|
|
20301
20462
|
dvm_id: dvmId,
|
|
20302
|
-
builder_pubkey:
|
|
20463
|
+
builder_pubkey: createHash10("sha256").update(`dvmkit-dev:${dvmId}`).digest("hex")
|
|
20303
20464
|
};
|
|
20304
20465
|
}
|
|
20305
20466
|
throw new AuthAudienceError();
|
|
@@ -20647,7 +20808,7 @@ var DVMServer = class {
|
|
|
20647
20808
|
const paymentAuthorization = ctx.req.header("Authorization");
|
|
20648
20809
|
const mppArtifact = paymentAuthorization ? (await import("mppx")).Credential.extractPaymentScheme(paymentAuthorization) : void 0;
|
|
20649
20810
|
const attachedPayment = ctx.req.header("X-Cashu") ?? ctx.req.header("PAYMENT-SIGNATURE") ?? ctx.req.header("X-PAYMENT") ?? mppArtifact;
|
|
20650
|
-
const paymentArtifactHash = attachedPayment ?
|
|
20811
|
+
const paymentArtifactHash = attachedPayment ? createHash10("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
20651
20812
|
hostingFundingArtifactHash = paymentArtifactHash;
|
|
20652
20813
|
if (!await control.admit(admissionId, workId, {
|
|
20653
20814
|
creditId,
|
|
@@ -20791,7 +20952,7 @@ var DVMServer = class {
|
|
|
20791
20952
|
// sees only the shortened list cannot tell a DVM that never did
|
|
20792
20953
|
// sessions from one whose observer is down for a minute.
|
|
20793
20954
|
...withheld.length && { withheld },
|
|
20794
|
-
realm: this.opts.mpp.realm,
|
|
20955
|
+
...this.opts.mpp.realm && { realm: this.opts.mpp.realm },
|
|
20795
20956
|
...this.opts.mpp.tempoConfiguration && {
|
|
20796
20957
|
recipient: this.opts.mpp.tempoConfiguration.recipient,
|
|
20797
20958
|
payment_token: this.opts.mpp.tempoConfiguration.paymentToken,
|
|
@@ -20831,17 +20992,20 @@ var DVMServer = class {
|
|
|
20831
20992
|
entry.input_schema = toJSONSchema(cap.input, { io: "input" });
|
|
20832
20993
|
}
|
|
20833
20994
|
if (cap.example !== void 0) entry.example = cap.example;
|
|
20995
|
+
let pricing;
|
|
20834
20996
|
if (cap.onQuote?.schema) {
|
|
20835
20997
|
const qs = cap.onQuote.schema;
|
|
20836
|
-
|
|
20998
|
+
pricing = {
|
|
20837
20999
|
quote: {
|
|
20838
21000
|
schema: isZodSchema(qs) ? toJSONSchema(qs, { io: "input" }) : qs
|
|
20839
21001
|
}
|
|
20840
21002
|
};
|
|
20841
21003
|
} else {
|
|
20842
21004
|
const max = this.jobManager.currentPricingMax(name);
|
|
20843
|
-
if (max)
|
|
21005
|
+
if (max) pricing = { max };
|
|
20844
21006
|
}
|
|
21007
|
+
if (cap.rates) pricing = { ...pricing, rates: cap.rates };
|
|
21008
|
+
if (pricing) entry.pricing = pricing;
|
|
20845
21009
|
out[name] = entry;
|
|
20846
21010
|
}
|
|
20847
21011
|
return out;
|
|
@@ -21353,7 +21517,7 @@ var DVMServer = class {
|
|
|
21353
21517
|
const authorization = c.req.header("Authorization");
|
|
21354
21518
|
const mppArtifact = authorization ? (await import("mppx")).Credential.extractPaymentScheme(authorization) : void 0;
|
|
21355
21519
|
const attachedPayment = c.req.header("X-Cashu") ?? c.req.header("PAYMENT-SIGNATURE") ?? c.req.header("X-PAYMENT") ?? mppArtifact;
|
|
21356
|
-
const hostingPaymentArtifactHash = attachedPayment ?
|
|
21520
|
+
const hostingPaymentArtifactHash = attachedPayment ? createHash10("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
21357
21521
|
if (!resumeOnly && this.opts.hostingControlInstance && hostingPaymentArtifactHash) {
|
|
21358
21522
|
const priorId = await this.opts.hostingControlInstance.acceptedJobByPaymentArtifactHash(
|
|
21359
21523
|
hostingPaymentArtifactHash
|
|
@@ -21651,7 +21815,7 @@ var DVMServer = class {
|
|
|
21651
21815
|
}
|
|
21652
21816
|
const isAnonymous = requesterId === "anonymous" || requesterId === "dev-anonymous";
|
|
21653
21817
|
const jobToken = isAnonymous ? randomBytes5(32).toString("hex") : void 0;
|
|
21654
|
-
const requesterTokenHash = jobToken ?
|
|
21818
|
+
const requesterTokenHash = jobToken ? createHash10("sha256").update(jobToken).digest("hex") : void 0;
|
|
21655
21819
|
const job = jm.createJob(
|
|
21656
21820
|
normalisedBody,
|
|
21657
21821
|
requesterId,
|
|
@@ -22363,7 +22527,7 @@ function isJobOwner(c, job) {
|
|
|
22363
22527
|
if (job.requesterTokenHash) {
|
|
22364
22528
|
const token = c.req.header("X-Job-Token");
|
|
22365
22529
|
if (!token) return false;
|
|
22366
|
-
const provided =
|
|
22530
|
+
const provided = createHash10("sha256").update(token).digest("hex");
|
|
22367
22531
|
return timingSafeEqualHex(provided, job.requesterTokenHash);
|
|
22368
22532
|
}
|
|
22369
22533
|
return c.get("requesterId") === job.requesterId;
|
|
@@ -22381,7 +22545,7 @@ function buildSubmitResponse(c, job, jobToken, contentFields) {
|
|
|
22381
22545
|
else if (job.status === "completed") res.status = "completed";
|
|
22382
22546
|
Object.assign(res, terminalResponseFields(job), contentFields);
|
|
22383
22547
|
removeUnavailableContent(res);
|
|
22384
|
-
return c.json(res, job.status === "completed" ? 200 : 202);
|
|
22548
|
+
return c.json(res, job.status === "completed" ? 200 : 202, jobIdentityHeaders(job.id));
|
|
22385
22549
|
}
|
|
22386
22550
|
function requestRecoveryStore(store) {
|
|
22387
22551
|
return store.findJobByRequestId && store.claimRequestId && store.resumeRequestId && store.releaseRequestIdClaim ? store : void 0;
|
|
@@ -22447,7 +22611,10 @@ function buildRequestResultResponse(c, requestId, job, contentFields) {
|
|
|
22447
22611
|
if (job.paymentTransactionHash) res.transaction_hash = job.paymentTransactionHash;
|
|
22448
22612
|
Object.assign(res, terminalResponseFields(job), contentFields);
|
|
22449
22613
|
removeUnavailableContent(res);
|
|
22450
|
-
return c.json(res, isTerminal(job.status) ? 200 : 202);
|
|
22614
|
+
return c.json(res, isTerminal(job.status) ? 200 : 202, jobIdentityHeaders(job.id));
|
|
22615
|
+
}
|
|
22616
|
+
function jobIdentityHeaders(jobId) {
|
|
22617
|
+
return isJobIdentityValue(jobId) ? { [JOB_IDENTITY_HEADER]: jobId } : {};
|
|
22451
22618
|
}
|
|
22452
22619
|
function requestResultNotFound(c, requestId) {
|
|
22453
22620
|
return c.json(
|
|
@@ -22638,6 +22805,55 @@ function validateMessageContent(type, content, devMode) {
|
|
|
22638
22805
|
}
|
|
22639
22806
|
return null;
|
|
22640
22807
|
}
|
|
22808
|
+
var MAX_RATES = 5;
|
|
22809
|
+
var MAX_RATE_AMOUNT_LENGTH = 12;
|
|
22810
|
+
var MAX_RATE_TEXT_LENGTH = 24;
|
|
22811
|
+
var RATE_AMOUNT_RE = /^\d+(\.\d+)?$/;
|
|
22812
|
+
var RATE_KEYS = /* @__PURE__ */ new Set(["label", "amount", "currency", "per"]);
|
|
22813
|
+
function assertCapabilityRates(capabilities) {
|
|
22814
|
+
for (const [name, cap] of Object.entries(capabilities)) {
|
|
22815
|
+
if (cap.rates === void 0) continue;
|
|
22816
|
+
const refuse = (detail) => {
|
|
22817
|
+
throw new Error(`createDVMServer: capability ${JSON.stringify(name)}: ${detail}`);
|
|
22818
|
+
};
|
|
22819
|
+
const rates = cap.rates;
|
|
22820
|
+
if (!Array.isArray(rates) || rates.length === 0 || rates.length > MAX_RATES) {
|
|
22821
|
+
refuse(`rates must be an array of 1 to ${MAX_RATES} entries`);
|
|
22822
|
+
}
|
|
22823
|
+
if (cap.price === void 0 && cap.onQuote === void 0) {
|
|
22824
|
+
refuse("rates is declared on a free capability; set `price` or `onQuote`, or remove `rates`");
|
|
22825
|
+
}
|
|
22826
|
+
rates.forEach((rate, i) => {
|
|
22827
|
+
const at = `rates[${i}]`;
|
|
22828
|
+
if (typeof rate !== "object" || rate === null || Array.isArray(rate)) {
|
|
22829
|
+
refuse(`${at} must be an object with amount, currency and per`);
|
|
22830
|
+
}
|
|
22831
|
+
const entry = rate;
|
|
22832
|
+
for (const key of Object.keys(entry)) {
|
|
22833
|
+
if (!RATE_KEYS.has(key)) refuse(`${at}.${key} is not a rate field (label, amount, currency, per)`);
|
|
22834
|
+
}
|
|
22835
|
+
const amount = entry.amount;
|
|
22836
|
+
if (typeof amount !== "string" || amount.length > MAX_RATE_AMOUNT_LENGTH || !RATE_AMOUNT_RE.test(amount) || // Above zero without parsing to a float: some digit is non-zero.
|
|
22837
|
+
!/[1-9]/.test(amount)) {
|
|
22838
|
+
refuse(
|
|
22839
|
+
`${at}.amount must be a decimal dollar string above zero of at most ${MAX_RATE_AMOUNT_LENGTH} characters, like "0.00015" (got ${JSON.stringify(amount)})`
|
|
22840
|
+
);
|
|
22841
|
+
}
|
|
22842
|
+
if (entry.currency !== "USD") {
|
|
22843
|
+
refuse(`${at}.currency must be "USD" (got ${JSON.stringify(entry.currency)})`);
|
|
22844
|
+
}
|
|
22845
|
+
assertRateText(entry.per, `${at}.per`, refuse);
|
|
22846
|
+
if (entry.label !== void 0) assertRateText(entry.label, `${at}.label`, refuse);
|
|
22847
|
+
});
|
|
22848
|
+
}
|
|
22849
|
+
}
|
|
22850
|
+
function assertRateText(value, field, refuse) {
|
|
22851
|
+
if (typeof value !== "string" || value.length === 0 || value.length > MAX_RATE_TEXT_LENGTH || value.trim() !== value) {
|
|
22852
|
+
refuse(
|
|
22853
|
+
`${field} must be a string of 1 to ${MAX_RATE_TEXT_LENGTH} characters with no leading or trailing whitespace (got ${JSON.stringify(value)})`
|
|
22854
|
+
);
|
|
22855
|
+
}
|
|
22856
|
+
}
|
|
22641
22857
|
|
|
22642
22858
|
// src/sdk/server/tempo-observer-health.ts
|
|
22643
22859
|
var TEMPO_OBSERVER_HEALTH_REFRESH_TTL_MS = 60 * 1e3;
|
|
@@ -22850,6 +23066,7 @@ export {
|
|
|
22850
23066
|
derivedFundCreditId,
|
|
22851
23067
|
drawSettlementRef,
|
|
22852
23068
|
rateUnavailablePaymentError,
|
|
23069
|
+
isTestMintUrl,
|
|
22853
23070
|
X402_BATCH_SETTLEMENT_NETWORK,
|
|
22854
23071
|
X402_BATCH_SETTLEMENT_MAINNET_NETWORK,
|
|
22855
23072
|
X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS,
|