@dvmkit/sdk 0.7.0-rc.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +1 -1
- package/README.md +57 -261
- package/dist/{chunk-RJFBBEWQ.js → chunk-2I3OHMTY.js} +1 -1
- package/dist/{chunk-7RZEJJTN.js → chunk-55NKZQOC.js} +2 -2
- package/dist/{chunk-5CSR33B5.js → chunk-5CQKSLAU.js} +1 -1
- package/dist/{chunk-YS6PWVCZ.js → chunk-5K5E6ME6.js} +1 -1
- package/dist/chunk-66HGCPBU.js +25 -0
- package/dist/{chunk-QM2OS3NJ.js → chunk-6FEHRZO7.js} +1 -1
- package/dist/{chunk-FYETJDBB.js → chunk-ATXDKX6F.js} +2 -2
- package/dist/{chunk-RGSWVNQG.js → chunk-BL6LRWXD.js} +2 -43
- package/dist/{chunk-5PLQOC4B.js → chunk-DZQYQN2X.js} +2 -1
- package/dist/{chunk-YE53E4BT.js → chunk-EBCLWOKF.js} +1 -1
- package/dist/{chunk-KXWROQGK.js → chunk-FUJ36YDV.js} +1 -24
- package/dist/{chunk-QN3CQOE2.js → chunk-GB5XPAA5.js} +191 -5
- package/dist/{chunk-G7IXOVKV.js → chunk-GSPV3UIM.js} +98 -51
- package/dist/{chunk-2HAFZ5GC.js → chunk-I6PHA54S.js} +2 -2
- package/dist/chunk-IFWUWHTW.js +47 -0
- package/dist/{chunk-HU6ZMQDN.js → chunk-P5WEZXJ2.js} +1 -1
- package/dist/{chunk-2DE32RAW.js → chunk-PRSKC7AD.js} +1 -1
- package/dist/{chunk-6JZDFYQL.js → chunk-QPXI7YPH.js} +1 -1
- package/dist/{chunk-5TIFEMHJ.js → chunk-RTFBVXCN.js} +2 -2
- package/dist/{chunk-ZLWPEIE2.js → chunk-TFYY5APM.js} +1 -1
- package/dist/{chunk-IOKEKMIU.js → chunk-VYP6ADCS.js} +2 -2
- package/dist/{chunk-OFSOLHRX.js → chunk-WMGXJQI3.js} +1 -1
- package/dist/{chunk-YNHXOONR.js → chunk-X3JEME6P.js} +1 -1
- package/dist/{chunk-2GTLF74N.js → chunk-XXLUIXPO.js} +1 -1
- package/dist/{chunk-WGK5KZ6S.js → chunk-YPSJU3OH.js} +3 -3
- package/dist/{content-retention-U7dJM7Ph.d.ts → content-retention-D2K4MKNO.d.ts} +1 -1
- package/dist/{credit-ledger-F2LWQU6N.js → credit-ledger-AOU6S34N.js} +3 -3
- package/dist/{credit-menu-CUJdCfpt.d.ts → credit-menu-C-8g2cHT.d.ts} +5 -5
- package/dist/{fx-BvG2Wnjk.d.ts → fx-Ql4nvdbh.d.ts} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/internal/caller.d.ts +10 -8
- package/dist/internal/caller.js +12 -9
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +22 -20
- package/dist/{job-store-DjgN2AOk.d.ts → job-store-DCvJQUX0.d.ts} +1 -1
- package/dist/{lightning-backend-DeasHNOP.d.ts → lightning-backend-CY5ML3km.d.ts} +1 -1
- package/dist/{memory-credit-ledger-XOOWJTBZ.js → memory-credit-ledger-4HWYINKJ.js} +4 -4
- package/dist/{mpp-setup-KGX6PLAF.js → mpp-setup-2BKTPEK6.js} +4 -2
- package/dist/{payout-reporter-W3CCLYCN.js → payout-reporter-HQSIIBFL.js} +2 -2
- package/dist/{postgres-consumed-credential-store-LUJ5CUJS.js → postgres-consumed-credential-store-R7DNU6CM.js} +1 -1
- package/dist/{postgres-job-store-IX7IUXF4.js → postgres-job-store-6VGFL6XE.js} +2 -2
- package/dist/{postgres-replay-store-Q6MEQDWZ.js → postgres-replay-store-SY26NUCI.js} +2 -2
- package/dist/{pricing-ZUEFO3CM.js → pricing-H2RA4X2R.js} +3 -3
- package/dist/{revenue-reporter-NRS2FANA.js → revenue-reporter-X52GPZ5U.js} +2 -2
- package/dist/server/index.d.ts +10 -10
- package/dist/server/index.js +30 -28
- package/dist/{step-cache-C9JRSFhM.d.ts → step-cache-BOWAn_BH.d.ts} +32 -4
- package/dist/{tempo-charge-store-NZJTJCUO.js → tempo-charge-store-NKXJ2AXE.js} +2 -2
- package/dist/{tempo-session-store-ENFDLDKC.js → tempo-session-store-ZSDQIWSU.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +8 -6
- package/dist/{usd-DXDkHn_8.d.ts → usd-MAtMp3DB.d.ts} +1 -1
- package/dist/{x402-T7WVKDD4.js → x402-Q4S36NHQ.js} +6 -5
- package/package.json +18 -3
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loggers
|
|
3
|
+
} from "./chunk-BL6LRWXD.js";
|
|
1
4
|
import {
|
|
2
5
|
diagnosticConsole
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DZQYQN2X.js";
|
|
4
7
|
|
|
5
8
|
// src/sdk/server/mpp-setup.ts
|
|
6
9
|
import { createHash, randomUUID } from "crypto";
|
|
@@ -533,7 +536,7 @@ function buildMppMethods(opts, env) {
|
|
|
533
536
|
})
|
|
534
537
|
);
|
|
535
538
|
if (opts.tempoSession) {
|
|
536
|
-
methods.push(
|
|
539
|
+
methods.push(withAuthenticationOnlyValidation(
|
|
537
540
|
tempo.session({
|
|
538
541
|
recipient: opts.tempoRecipient,
|
|
539
542
|
account: opts.tempoSession.account,
|
|
@@ -557,12 +560,25 @@ function buildMppMethods(opts, env) {
|
|
|
557
560
|
onSessionSettlement: opts.tempoSession.onSessionSettlement
|
|
558
561
|
}
|
|
559
562
|
})
|
|
560
|
-
);
|
|
563
|
+
));
|
|
561
564
|
}
|
|
562
565
|
}
|
|
563
566
|
if (methods.length === 0 || !tempoConfiguration) return void 0;
|
|
564
567
|
return { methods, tempoConfiguration };
|
|
565
568
|
}
|
|
569
|
+
function withAuthenticationOnlyValidation(method) {
|
|
570
|
+
if (method.validate) return method;
|
|
571
|
+
const validate = async ({ credential, request }) => ({
|
|
572
|
+
challenge: credential.challenge,
|
|
573
|
+
credential,
|
|
574
|
+
details: void 0,
|
|
575
|
+
intent: method.intent,
|
|
576
|
+
method: method.name,
|
|
577
|
+
request,
|
|
578
|
+
...credential.source !== void 0 && { source: credential.source }
|
|
579
|
+
});
|
|
580
|
+
return { ...method, validate };
|
|
581
|
+
}
|
|
566
582
|
function resolveTempoNetwork(env) {
|
|
567
583
|
const testnet = env.DVMKIT_TEMPO_TESTNET === "1" || env.DVMKIT_TEMPO_TESTNET === "true";
|
|
568
584
|
const rawChainId = env.DVMKIT_TEMPO_CHAIN_ID?.trim();
|
|
@@ -612,6 +628,9 @@ function wrapMppx(mppx) {
|
|
|
612
628
|
};
|
|
613
629
|
return Object.assign(server, { issueChallenge });
|
|
614
630
|
}
|
|
631
|
+
var TEMPO_CLOSE_LOG_WINDOW = 5000n;
|
|
632
|
+
var TEMPO_CLOSE_LOG_SLACK_MS = 10 * 60 * 1e3;
|
|
633
|
+
var TEMPO_CLOSE_LOG_MAX_WINDOWS = 500;
|
|
615
634
|
var DEFAULT_TEMPO_SESSION_CHAIN_OPS = {
|
|
616
635
|
getChannelStatesBatch: TempoSession.Precompile.Chain.getChannelStatesBatch,
|
|
617
636
|
settle: TempoSession.Server.settle,
|
|
@@ -621,7 +640,32 @@ var DEFAULT_TEMPO_SESSION_CHAIN_OPS = {
|
|
|
621
640
|
"ChannelClosed",
|
|
622
641
|
channelId
|
|
623
642
|
)
|
|
624
|
-
)
|
|
643
|
+
),
|
|
644
|
+
findChannelClose: async (client, channelId, escrowContract, notBeforeMs) => {
|
|
645
|
+
const { getBlock, getBlockNumber, getLogs } = await import("viem/actions");
|
|
646
|
+
const event = TempoSession.Precompile.escrowAbi.find(
|
|
647
|
+
(item) => item.type === "event" && item.name === "ChannelClosed"
|
|
648
|
+
);
|
|
649
|
+
if (!event || event.type !== "event") throw new Error("Tempo escrow ABI has no ChannelClosed event");
|
|
650
|
+
let toBlock = await getBlockNumber(client);
|
|
651
|
+
for (let window = 0; window < TEMPO_CLOSE_LOG_MAX_WINDOWS; window += 1) {
|
|
652
|
+
const fromBlock = toBlock >= TEMPO_CLOSE_LOG_WINDOW ? toBlock - TEMPO_CLOSE_LOG_WINDOW + 1n : 0n;
|
|
653
|
+
const logs = await getLogs(client, {
|
|
654
|
+
address: escrowContract,
|
|
655
|
+
event,
|
|
656
|
+
args: { channelId },
|
|
657
|
+
fromBlock,
|
|
658
|
+
toBlock
|
|
659
|
+
});
|
|
660
|
+
const closed = logs.find((log) => log.transactionHash);
|
|
661
|
+
if (closed?.transactionHash) return closed.transactionHash;
|
|
662
|
+
if (fromBlock === 0n) return null;
|
|
663
|
+
const start = await getBlock(client, { blockNumber: fromBlock });
|
|
664
|
+
if (Number(start.timestamp) * 1e3 < notBeforeMs - TEMPO_CLOSE_LOG_SLACK_MS) return null;
|
|
665
|
+
toBlock = fromBlock - 1n;
|
|
666
|
+
}
|
|
667
|
+
throw new Error(`Tempo close search for channel ${channelId} exceeded its block budget`);
|
|
668
|
+
}
|
|
625
669
|
};
|
|
626
670
|
function attachTempoSessionRuntime(mppx, config, chainOpOverrides = {}) {
|
|
627
671
|
let creditLedger;
|
|
@@ -642,6 +686,102 @@ function attachTempoSessionRuntime(mppx, config, chainOpOverrides = {}) {
|
|
|
642
686
|
}
|
|
643
687
|
if (store) {
|
|
644
688
|
Object.assign(mppx, {
|
|
689
|
+
assertTempoSessionCloseVoucher: async (voucher) => {
|
|
690
|
+
const descriptor = readChannelDescriptor(voucher.descriptor);
|
|
691
|
+
if (!descriptor) {
|
|
692
|
+
throw new MppxErrors.VerificationFailedError({
|
|
693
|
+
reason: "descriptor required for TIP-1034 session action"
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
const details = isStateRecord(voucher.request.methodDetails) ? voucher.request.methodDetails : {};
|
|
697
|
+
const stored = await store.get(voucher.channelId.toLowerCase());
|
|
698
|
+
const state = readTempoSessionState(stored);
|
|
699
|
+
const chainId = typeof details.chainId === "number" ? details.chainId : state?.chainId;
|
|
700
|
+
const escrow = typeof details.escrowContract === "string" ? details.escrowContract : state?.escrowContract;
|
|
701
|
+
if (chainId === void 0 || escrow === void 0) {
|
|
702
|
+
throw new MppxErrors.VerificationFailedError({ reason: "invalid session request" });
|
|
703
|
+
}
|
|
704
|
+
const computed = TempoSession.Precompile.Channel.computeId({
|
|
705
|
+
...descriptor,
|
|
706
|
+
chainId,
|
|
707
|
+
escrow
|
|
708
|
+
});
|
|
709
|
+
if (computed.toLowerCase() !== voucher.channelId.toLowerCase()) {
|
|
710
|
+
throw new MppxErrors.VerificationFailedError({
|
|
711
|
+
reason: "channel descriptor does not match channelId"
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
if (!sameHex(descriptor.payee, voucher.request.recipient)) {
|
|
715
|
+
throw new MppxErrors.VerificationFailedError({
|
|
716
|
+
reason: "channel descriptor payee does not match server destination"
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
if (!sameHex(descriptor.token, voucher.request.currency)) {
|
|
720
|
+
throw new MppxErrors.VerificationFailedError({
|
|
721
|
+
reason: "channel descriptor token does not match server token"
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
if (!sameHex(descriptor.operator, details.operator ?? ZERO_ADDRESS)) {
|
|
725
|
+
throw new MppxErrors.VerificationFailedError({
|
|
726
|
+
reason: "channel descriptor operator does not match server operator"
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
if (!state || !isStateRecord(stored)) {
|
|
730
|
+
throw new MppxErrors.ChannelNotFoundError({ reason: "channel not found" });
|
|
731
|
+
}
|
|
732
|
+
if (stored.backend !== "precompile") {
|
|
733
|
+
throw new MppxErrors.VerificationFailedError({
|
|
734
|
+
reason: "channel is not precompile-backed"
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
const storedDescriptor = readChannelDescriptor(stored.descriptor);
|
|
738
|
+
if (!storedDescriptor || !sameDescriptor(descriptor, storedDescriptor)) {
|
|
739
|
+
throw new MppxErrors.VerificationFailedError({
|
|
740
|
+
reason: "credential descriptor does not match stored channel"
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
const signer = stored.authorizedSigner;
|
|
744
|
+
if (typeof signer !== "string" || !HEX_ADDRESS_RE.test(signer)) {
|
|
745
|
+
throw new MppxErrors.ChannelNotFoundError({ reason: "channel not found" });
|
|
746
|
+
}
|
|
747
|
+
if (state.finalized) {
|
|
748
|
+
throw new MppxErrors.ChannelClosedError({ reason: "channel is already finalized" });
|
|
749
|
+
}
|
|
750
|
+
if (state.closeRequestedAt !== 0n) {
|
|
751
|
+
throw new MppxErrors.ChannelClosedError({ reason: "channel has a pending close request" });
|
|
752
|
+
}
|
|
753
|
+
if (state.deposit === 0n && (voucher.cumulativeAmount !== 0n || state.spent !== 0n)) {
|
|
754
|
+
throw new MppxErrors.ChannelClosedError({ reason: "channel deposit is zero (settled)" });
|
|
755
|
+
}
|
|
756
|
+
if (voucher.cumulativeAmount < state.spent) {
|
|
757
|
+
throw new MppxErrors.VerificationFailedError({
|
|
758
|
+
reason: `close voucher amount must be >= ${state.spent} (spent)`
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
if (voucher.cumulativeAmount < state.settledOnChain) {
|
|
762
|
+
throw new MppxErrors.VerificationFailedError({
|
|
763
|
+
reason: `close voucher amount must be >= ${state.settledOnChain} (on-chain settled)`
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
const valid = TempoSession.Precompile.Voucher.verifyVoucher(
|
|
767
|
+
escrow,
|
|
768
|
+
chainId,
|
|
769
|
+
{
|
|
770
|
+
channelId: voucher.channelId,
|
|
771
|
+
cumulativeAmount: voucher.cumulativeAmount,
|
|
772
|
+
signature: voucher.signature
|
|
773
|
+
},
|
|
774
|
+
signer
|
|
775
|
+
);
|
|
776
|
+
if (!valid) {
|
|
777
|
+
throw new MppxErrors.InvalidSignatureError({ reason: "invalid voucher signature" });
|
|
778
|
+
}
|
|
779
|
+
if (maxBigInt(state.spent, state.settledOnChain) > state.deposit) {
|
|
780
|
+
throw new MppxErrors.AmountExceedsDepositError({
|
|
781
|
+
reason: "close capture amount exceeds on-chain deposit"
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
},
|
|
645
785
|
getTempoSessionSpent: async (channelId) => {
|
|
646
786
|
const state = readTempoSessionState(await store.get(channelId.toLowerCase()));
|
|
647
787
|
if (!state) throw new Error(`Tempo session channel ${channelId} not found`);
|
|
@@ -984,7 +1124,32 @@ function attachTempoSessionRuntime(mppx, config, chainOpOverrides = {}) {
|
|
|
984
1124
|
finalized = chainState.deposit === 0n;
|
|
985
1125
|
}
|
|
986
1126
|
if (!finalized) return null;
|
|
987
|
-
const
|
|
1127
|
+
const pending = await config.hostedObligations?.pendingTempoClose(channelId, drainId);
|
|
1128
|
+
let reference = pending?.txHash ?? void 0;
|
|
1129
|
+
if (pending && !reference) {
|
|
1130
|
+
const client = await getClient({ chainId: current.chainId });
|
|
1131
|
+
const txHash = await chainOps.findChannelClose(
|
|
1132
|
+
client,
|
|
1133
|
+
current.channelId,
|
|
1134
|
+
current.escrowContract,
|
|
1135
|
+
pending.reservedAtMs
|
|
1136
|
+
);
|
|
1137
|
+
if (txHash) {
|
|
1138
|
+
await config.hostedObligations.recordSubmitted(pending.id, txHash);
|
|
1139
|
+
reference = txHash;
|
|
1140
|
+
} else {
|
|
1141
|
+
loggers.tempo.warn("tempo_session_close_recovery_unmatched", {
|
|
1142
|
+
channel_id: current.channelId,
|
|
1143
|
+
drain_id: drainId,
|
|
1144
|
+
obligation_id: pending.id
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
const recovered = await store.confirmClose(
|
|
1149
|
+
channelId,
|
|
1150
|
+
drainId,
|
|
1151
|
+
reference ?? `channel:${channelId}`
|
|
1152
|
+
);
|
|
988
1153
|
return recovered.reference;
|
|
989
1154
|
};
|
|
990
1155
|
const getClose = store.getClose?.bind(store) ?? (() => Promise.resolve(null));
|
|
@@ -1028,6 +1193,27 @@ function maxBigInt(left, right) {
|
|
|
1028
1193
|
function isStateRecord(value) {
|
|
1029
1194
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1030
1195
|
}
|
|
1196
|
+
var ZERO_ADDRESS = `0x${"00".repeat(20)}`;
|
|
1197
|
+
var DESCRIPTOR_ADDRESSES = ["payer", "payee", "operator", "token", "authorizedSigner"];
|
|
1198
|
+
var DESCRIPTOR_WORDS = ["salt", "expiringNonceHash"];
|
|
1199
|
+
function readChannelDescriptor(value) {
|
|
1200
|
+
if (!isStateRecord(value)) return void 0;
|
|
1201
|
+
for (const field of DESCRIPTOR_ADDRESSES) {
|
|
1202
|
+
if (typeof value[field] !== "string" || !HEX_ADDRESS_RE.test(value[field])) return void 0;
|
|
1203
|
+
}
|
|
1204
|
+
for (const field of DESCRIPTOR_WORDS) {
|
|
1205
|
+
if (typeof value[field] !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(value[field])) {
|
|
1206
|
+
return void 0;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return value;
|
|
1210
|
+
}
|
|
1211
|
+
function sameHex(left, right) {
|
|
1212
|
+
return typeof left === "string" && typeof right === "string" && left.toLowerCase() === right.toLowerCase();
|
|
1213
|
+
}
|
|
1214
|
+
function sameDescriptor(left, right) {
|
|
1215
|
+
return DESCRIPTOR_ADDRESSES.every((field) => sameHex(left[field], right[field])) && DESCRIPTOR_WORDS.every((field) => sameHex(left[field], right[field]));
|
|
1216
|
+
}
|
|
1031
1217
|
function tempoSettlementDue(args) {
|
|
1032
1218
|
const { channel, chainSettled, forcedClose, intervalMs } = args;
|
|
1033
1219
|
const settlementBoundary = Date.parse(channel.lastSettlementAt ?? channel.createdAt ?? "");
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
installHostedTempoCloseGuard,
|
|
8
8
|
isTempoInsufficientFundsError,
|
|
9
9
|
resolveTempoNetwork
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GB5XPAA5.js";
|
|
11
11
|
import {
|
|
12
12
|
x402EarnedCeiling
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-X3JEME6P.js";
|
|
14
14
|
import {
|
|
15
15
|
createX402FacilitatorAuthHeaders,
|
|
16
16
|
createX402FacilitatorClient,
|
|
@@ -19,13 +19,13 @@ import {
|
|
|
19
19
|
verifyWithFacilitator,
|
|
20
20
|
withPaymentDiagnostics,
|
|
21
21
|
withPaymentStage
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-ATXDKX6F.js";
|
|
23
23
|
import {
|
|
24
24
|
MemoryCreditLedger
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-EBCLWOKF.js";
|
|
26
26
|
import {
|
|
27
27
|
PostgresJobStore
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-QPXI7YPH.js";
|
|
29
29
|
import {
|
|
30
30
|
parseStoreValue
|
|
31
31
|
} from "./chunk-YG7G4DPZ.js";
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
humanizeZodIssues,
|
|
37
37
|
signedRequestInput,
|
|
38
38
|
zodIssuesOf
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-5K5E6ME6.js";
|
|
40
40
|
import {
|
|
41
41
|
MemoryJobStore,
|
|
42
42
|
UNCAPPABLE_ASK_TOTAL,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
isJobRetentionStore,
|
|
46
46
|
isReceiptIssuingStore,
|
|
47
47
|
isStreamableJobStore
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-I6PHA54S.js";
|
|
49
49
|
import {
|
|
50
50
|
ContentHoldError,
|
|
51
51
|
JobCancelledError,
|
|
@@ -85,7 +85,7 @@ import {
|
|
|
85
85
|
signReceipt,
|
|
86
86
|
toLockPubkey,
|
|
87
87
|
verifyChallenge
|
|
88
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-RTFBVXCN.js";
|
|
89
89
|
import {
|
|
90
90
|
X402_BATCH_SETTLEMENT_SCHEME,
|
|
91
91
|
X402_DEFAULT_FACILITATOR,
|
|
@@ -112,12 +112,14 @@ import {
|
|
|
112
112
|
isZodSchema
|
|
113
113
|
} from "./chunk-UKD3R2KU.js";
|
|
114
114
|
import {
|
|
115
|
-
createConsoleLogger
|
|
115
|
+
createConsoleLogger
|
|
116
|
+
} from "./chunk-IFWUWHTW.js";
|
|
117
|
+
import {
|
|
116
118
|
loggers,
|
|
117
119
|
pinDimension,
|
|
118
120
|
withSpan,
|
|
119
121
|
withTraceContext
|
|
120
|
-
} from "./chunk-
|
|
122
|
+
} from "./chunk-BL6LRWXD.js";
|
|
121
123
|
import {
|
|
122
124
|
StepCache
|
|
123
125
|
} from "./chunk-BQJIFRAZ.js";
|
|
@@ -134,7 +136,7 @@ import {
|
|
|
134
136
|
roundUsd,
|
|
135
137
|
satsToFiat,
|
|
136
138
|
validateCurrency
|
|
137
|
-
} from "./chunk-
|
|
139
|
+
} from "./chunk-5CQKSLAU.js";
|
|
138
140
|
import {
|
|
139
141
|
CreditLedger,
|
|
140
142
|
CreditLedgerError,
|
|
@@ -150,10 +152,10 @@ import {
|
|
|
150
152
|
isNonChannelBitcoinRail,
|
|
151
153
|
netOwedSats,
|
|
152
154
|
x402SettlementPending
|
|
153
|
-
} from "./chunk-
|
|
155
|
+
} from "./chunk-VYP6ADCS.js";
|
|
154
156
|
import {
|
|
155
157
|
withPostgresRecoveryContext
|
|
156
|
-
} from "./chunk-
|
|
158
|
+
} from "./chunk-6FEHRZO7.js";
|
|
157
159
|
import {
|
|
158
160
|
DvmError,
|
|
159
161
|
x402NetworkByCaip2
|
|
@@ -161,7 +163,7 @@ import {
|
|
|
161
163
|
import {
|
|
162
164
|
createDiagnosticCapabilityAuthority,
|
|
163
165
|
diagnosticConsole
|
|
164
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-DZQYQN2X.js";
|
|
165
167
|
import {
|
|
166
168
|
MemoryProcessedPaymentStore,
|
|
167
169
|
PostgresProcessedPaymentStore,
|
|
@@ -3118,6 +3120,10 @@ function decodeBatchPayment(header) {
|
|
|
3118
3120
|
if (!isBatchSettlementDepositPayload2(parsed.payload) && !isBatchSettlementVoucherPayload(parsed.payload) && !isBatchSettlementRefundPayload2(parsed.payload)) {
|
|
3119
3121
|
throw new Error("invalid batch-settlement payload");
|
|
3120
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
|
+
}
|
|
3121
3127
|
return parsed;
|
|
3122
3128
|
}
|
|
3123
3129
|
function batchVoucher(payload) {
|
|
@@ -3877,7 +3883,7 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
3877
3883
|
x402Requirements
|
|
3878
3884
|
});
|
|
3879
3885
|
}
|
|
3880
|
-
const { verifyX402Payment } = await import("./x402-
|
|
3886
|
+
const { verifyX402Payment } = await import("./x402-Q4S36NHQ.js");
|
|
3881
3887
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
3882
3888
|
x402Payment,
|
|
3883
3889
|
x402Config,
|
|
@@ -4040,6 +4046,30 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
4040
4046
|
}
|
|
4041
4047
|
const expectedAmount = opts.priceFiat?.currency === "usd" ? fiatMicroToMethodAmount(opts.priceFiat.amountMicro, cred.challenge.method) : msatsToMethodAmount(requiredMsats, cred.challenge.method, rate);
|
|
4042
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
|
+
}
|
|
4043
4073
|
let tempoReceipt;
|
|
4044
4074
|
const broadcast = async () => {
|
|
4045
4075
|
const receipt = await loggers.tempo.span(
|
|
@@ -4157,35 +4187,12 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
4157
4187
|
}
|
|
4158
4188
|
};
|
|
4159
4189
|
}
|
|
4160
|
-
if (consumedCredentialStore) {
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
requiredMsats,
|
|
4167
|
-
resourcePath ?? "/v1/job",
|
|
4168
|
-
rate,
|
|
4169
|
-
sessionIssuable,
|
|
4170
|
-
opts.fundOnly?.allowOneShotStablecoin,
|
|
4171
|
-
opts.priceFiat
|
|
4172
|
-
);
|
|
4173
|
-
return {
|
|
4174
|
-
paidMsats: 0,
|
|
4175
|
-
receivedProofs: [],
|
|
4176
|
-
error: {
|
|
4177
|
-
body: paymentErrorBody("payment_invalid", {
|
|
4178
|
-
message: "MPP credential already used"
|
|
4179
|
-
}),
|
|
4180
|
-
status: 402,
|
|
4181
|
-
mppChallenges,
|
|
4182
|
-
...x402Requirements && { x402Requirements }
|
|
4183
|
-
}
|
|
4184
|
-
};
|
|
4185
|
-
}
|
|
4186
|
-
if (!sessionBasis) {
|
|
4187
|
-
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(realm, id, CONSUMED_CREDENTIAL_TTL_MS / 1e3));
|
|
4188
|
-
}
|
|
4190
|
+
if (consumedCredentialStore && !sessionBasis) {
|
|
4191
|
+
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(
|
|
4192
|
+
replayRealm,
|
|
4193
|
+
cred.challenge.id,
|
|
4194
|
+
CONSUMED_CREDENTIAL_TTL_MS / 1e3
|
|
4195
|
+
));
|
|
4189
4196
|
}
|
|
4190
4197
|
if (ledgerCtx) {
|
|
4191
4198
|
try {
|
|
@@ -4208,10 +4215,18 @@ async function verifyUpfrontPaymentInScope(opts) {
|
|
|
4208
4215
|
}
|
|
4209
4216
|
if (sessionBasis && consumedCredentialStore) {
|
|
4210
4217
|
await withPaymentStage("replay_store", () => consumedCredentialStore.mark(
|
|
4211
|
-
|
|
4218
|
+
replayRealm,
|
|
4212
4219
|
cred.challenge.id,
|
|
4213
4220
|
CONSUMED_CREDENTIAL_TTL_MS / 1e3
|
|
4214
|
-
))
|
|
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
|
+
});
|
|
4215
4230
|
}
|
|
4216
4231
|
if (credited) {
|
|
4217
4232
|
await mpp.completeHostedTempoCharge?.(cred.challenge.id).catch((error) => {
|
|
@@ -4420,6 +4435,22 @@ async function verifyTempoSessionManagementCredential(args) {
|
|
|
4420
4435
|
throw new Error("Hosted Tempo close requires non-mutating credential validation");
|
|
4421
4436
|
}
|
|
4422
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
|
+
}
|
|
4423
4454
|
}
|
|
4424
4455
|
await args.onBound?.();
|
|
4425
4456
|
const receipt = await args.mpp.broadcastCredential(credential, verifyOptions);
|
|
@@ -4865,7 +4896,7 @@ async function verifyIncomingPaymentInScope(body, opts, snapshot) {
|
|
|
4865
4896
|
snapshot
|
|
4866
4897
|
});
|
|
4867
4898
|
}
|
|
4868
|
-
const { verifyX402Payment } = await import("./x402-
|
|
4899
|
+
const { verifyX402Payment } = await import("./x402-Q4S36NHQ.js");
|
|
4869
4900
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
4870
4901
|
body.content.x402_payment,
|
|
4871
4902
|
opts.x402Config,
|
|
@@ -5296,7 +5327,7 @@ async function processIncomingPaymentInScope(job, body, opts) {
|
|
|
5296
5327
|
try {
|
|
5297
5328
|
const requiredMsats = job.pendingPaymentMsats ?? 0;
|
|
5298
5329
|
const requiredUsdcMicro = job.pendingX402AmountUsdcMicro !== void 0 ? BigInt(job.pendingX402AmountUsdcMicro) : BigInt(msatsToUsdc(requiredMsats, rate));
|
|
5299
|
-
const { verifyX402Payment } = await import("./x402-
|
|
5330
|
+
const { verifyX402Payment } = await import("./x402-Q4S36NHQ.js");
|
|
5300
5331
|
const receipt = await withPaymentStage("verifier_broadcast", () => verifyX402Payment(
|
|
5301
5332
|
body.content.x402_payment,
|
|
5302
5333
|
opts.x402Config,
|
|
@@ -10062,6 +10093,18 @@ var HostedSettlementReportObligations = class {
|
|
|
10062
10093
|
);
|
|
10063
10094
|
return result.rows[0];
|
|
10064
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
|
+
}
|
|
10065
10108
|
async submittedIds(rail, operation, txHash, batchId) {
|
|
10066
10109
|
if (!hex(txHash, 32)) throw new Error("Hosted effect has no exact transaction hash");
|
|
10067
10110
|
const result = await this.pool.query(
|
|
@@ -10201,6 +10244,10 @@ var HostedSettlementReportObligations = class {
|
|
|
10201
10244
|
}));
|
|
10202
10245
|
}
|
|
10203
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 [];
|
|
10204
10251
|
const rows2 = await this.pool.query(
|
|
10205
10252
|
`SELECT obligation.id,settlement.settle_response AS response
|
|
10206
10253
|
FROM sdk_hosted_settlement_report_obligations obligation
|
|
@@ -19537,7 +19584,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19537
19584
|
}
|
|
19538
19585
|
}
|
|
19539
19586
|
if (!opts.onJobCompleted && platformToken && platformUrl && dvmId && opts.db) {
|
|
19540
|
-
const { RevenueReporter } = await import("./revenue-reporter-
|
|
19587
|
+
const { RevenueReporter } = await import("./revenue-reporter-X52GPZ5U.js");
|
|
19541
19588
|
const reporter = new RevenueReporter(
|
|
19542
19589
|
opts.db,
|
|
19543
19590
|
platformUrl,
|
|
@@ -19547,7 +19594,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
19547
19594
|
revenueReporter = reporter;
|
|
19548
19595
|
await reporter.init();
|
|
19549
19596
|
reporter.startRetryLoop();
|
|
19550
|
-
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-
|
|
19597
|
+
const { MemoryX402BatchStore, PayoutReporter } = await import("./payout-reporter-HQSIIBFL.js");
|
|
19551
19598
|
payoutReporter = new PayoutReporter({
|
|
19552
19599
|
dvmId,
|
|
19553
19600
|
db: opts.db,
|
|
@@ -20905,7 +20952,7 @@ var DVMServer = class {
|
|
|
20905
20952
|
// sees only the shortened list cannot tell a DVM that never did
|
|
20906
20953
|
// sessions from one whose observer is down for a minute.
|
|
20907
20954
|
...withheld.length && { withheld },
|
|
20908
|
-
realm: this.opts.mpp.realm,
|
|
20955
|
+
...this.opts.mpp.realm && { realm: this.opts.mpp.realm },
|
|
20909
20956
|
...this.opts.mpp.tempoConfiguration && {
|
|
20910
20957
|
recipient: this.opts.mpp.tempoConfiguration.recipient,
|
|
20911
20958
|
payment_token: this.opts.mpp.tempoConfiguration.paymentToken,
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./chunk-AFV77S4C.js";
|
|
6
6
|
import {
|
|
7
7
|
loggers
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BL6LRWXD.js";
|
|
9
9
|
import {
|
|
10
10
|
redactUrl
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-FUJ36YDV.js";
|
|
12
12
|
|
|
13
13
|
// src/sdk/server/job-store.ts
|
|
14
14
|
function accumulateAskedTopUp(prior, ask) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
emitDiagnostic,
|
|
3
|
+
projectDiagnosticFields
|
|
4
|
+
} from "./chunk-DZQYQN2X.js";
|
|
5
|
+
|
|
6
|
+
// src/sdk/logger.ts
|
|
7
|
+
function createConsoleLogger(_jobId) {
|
|
8
|
+
return {
|
|
9
|
+
debug(_message, data) {
|
|
10
|
+
emitDiagnostic("debug", "diagnostic.message", data);
|
|
11
|
+
},
|
|
12
|
+
info(_message, data) {
|
|
13
|
+
emitDiagnostic("info", "diagnostic.message", data);
|
|
14
|
+
},
|
|
15
|
+
warn(_message, data) {
|
|
16
|
+
emitDiagnostic("warn", "diagnostic.message", data);
|
|
17
|
+
},
|
|
18
|
+
error(_message, data) {
|
|
19
|
+
emitDiagnostic("error", "diagnostic.message", data);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function createStdoutLogger(context) {
|
|
24
|
+
const emit = (level) => (_message, data) => {
|
|
25
|
+
emitDiagnostic(level, "diagnostic.message", {
|
|
26
|
+
...projectDiagnosticFields(context),
|
|
27
|
+
...projectDiagnosticFields(data)
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
debug: emit("debug"),
|
|
32
|
+
info: emit("info"),
|
|
33
|
+
warn: emit("warn"),
|
|
34
|
+
error: emit("error")
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function createNoopLogger() {
|
|
38
|
+
const noop = () => {
|
|
39
|
+
};
|
|
40
|
+
return { debug: noop, info: noop, warn: noop, error: noop };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
createConsoleLogger,
|
|
45
|
+
createStdoutLogger,
|
|
46
|
+
createNoopLogger
|
|
47
|
+
};
|
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-UKD3R2KU.js";
|
|
4
4
|
import {
|
|
5
5
|
callerLoggers
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-66HGCPBU.js";
|
|
7
7
|
import {
|
|
8
8
|
DvmError
|
|
9
9
|
} from "./chunk-BPYMEMQX.js";
|
|
10
10
|
import {
|
|
11
11
|
diagnosticConsole
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DZQYQN2X.js";
|
|
13
13
|
|
|
14
14
|
// src/lib/cashu/lock-pubkey.ts
|
|
15
15
|
function toLockPubkey(raw) {
|