@dvmkit/sdk 0.4.0-rc.1 → 0.6.0-rc.1

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.
Files changed (43) hide show
  1. package/README.md +100 -0
  2. package/dist/{chunk-TXX4GOUB.js → chunk-7ZUKL4IV.js} +1 -1
  3. package/dist/chunk-AFV77S4C.js +258 -0
  4. package/dist/{chunk-2VGWYG4P.js → chunk-B2IROPQF.js} +446 -81
  5. package/dist/chunk-BQJIFRAZ.js +36 -0
  6. package/dist/{chunk-PB4FYZET.js → chunk-EQLA4FFY.js} +54 -4
  7. package/dist/{chunk-74PUEZJ4.js → chunk-GFY5FRX3.js} +1 -1
  8. package/dist/{chunk-O3QDFPKM.js → chunk-HCLVYZUZ.js} +2 -2
  9. package/dist/{chunk-K2YX2VRA.js → chunk-HHBDBMEO.js} +170 -43
  10. package/dist/{chunk-O5AT6S5T.js → chunk-IV6Q7NRW.js} +25 -195
  11. package/dist/{chunk-W2EQGDF5.js → chunk-LE74UEV7.js} +49 -8
  12. package/dist/{chunk-CE7XEHYC.js → chunk-N5RZ5HVB.js} +1 -1
  13. package/dist/chunk-OFVV37XC.js +57 -0
  14. package/dist/{chunk-5LR6P7WN.js → chunk-OQA7IHI4.js} +133 -213
  15. package/dist/{chunk-3MHE725Z.js → chunk-PAIM66YA.js} +90 -1
  16. package/dist/{chunk-6DOGTAHA.js → chunk-QR2EF2NI.js} +9 -43
  17. package/dist/{chunk-KXZUCCEY.js → chunk-RCM3P2HE.js} +5 -56
  18. package/dist/{chunk-R4DQZFAL.js → chunk-UOCZXO2Z.js} +3 -3
  19. package/dist/content-retention-BTGSQRfP.d.ts +78 -0
  20. package/dist/{credit-menu-B8_p_vUz.d.ts → credit-menu-BAsrRu3z.d.ts} +98 -5
  21. package/dist/{fx-DuaYHvVn.d.ts → fx-BgDmyTdd.d.ts} +1 -1
  22. package/dist/index.d.ts +5 -5
  23. package/dist/index.js +4 -3
  24. package/dist/internal/caller.d.ts +90 -22
  25. package/dist/internal/caller.js +40 -40
  26. package/dist/internal/index.js +1 -1
  27. package/dist/internal/server.d.ts +8 -99
  28. package/dist/internal/server.js +15 -11
  29. package/dist/{job-store-D6Rjj5Oi.d.ts → job-store-BVeF5_Jq.d.ts} +1 -1
  30. package/dist/{lightning-backend-BaeCPmx7.d.ts → lightning-backend-40fIzz1W.d.ts} +1 -1
  31. package/dist/{postgres-consumed-credential-store-CUQJKRSL.js → postgres-consumed-credential-store-BUVCAPLS.js} +13 -0
  32. package/dist/{postgres-job-store-VLXLWXUQ.js → postgres-job-store-VHLQBJZC.js} +3 -1
  33. package/dist/server/index.d.ts +28 -10
  34. package/dist/server/index.js +24 -10
  35. package/dist/{step-cache-Bi43A0JN.d.ts → step-cache-CPdH1hei.d.ts} +3 -3
  36. package/dist/{tempo-lifecycle-OTHV757Y.js → tempo-lifecycle-ZBBLFBMH.js} +5 -4
  37. package/dist/{tempo-wallet-32JWQZKQ.js → tempo-wallet-B5XXV3YH.js} +1 -1
  38. package/dist/testing/index.d.ts +9 -2
  39. package/dist/testing/index.js +6 -3
  40. package/dist/{usd-AZPVq4eU.d.ts → usd-AWlrwlM5.d.ts} +1 -1
  41. package/dist/{x402-CEDHGZDI.js → x402-R6HPBY5D.js} +5 -4
  42. package/package.json +3 -2
  43. package/recipes/postgres/financial-export-v1.sql +137 -0
@@ -1,8 +1,14 @@
1
1
  import {
2
+ computeResultHash,
2
3
  costAnchor,
3
4
  formatUsd,
4
- msatsToUsd
5
- } from "./chunk-3MHE725Z.js";
5
+ isDrainReceipt,
6
+ isFundingReceipt,
7
+ msatsToUsd,
8
+ verifyDrainReceipt,
9
+ verifyFundingReceipt,
10
+ verifyReceipt
11
+ } from "./chunk-PAIM66YA.js";
6
12
  import {
7
13
  AGENT_MNEMONIC_FILE,
8
14
  BUILDER_CONFIG_DIR,
@@ -13,7 +19,7 @@ import {
13
19
  } from "./chunk-CZULM42S.js";
14
20
  import {
15
21
  canonicaliseForSigning
16
- } from "./chunk-KXZUCCEY.js";
22
+ } from "./chunk-OFVV37XC.js";
17
23
  import {
18
24
  callerLoggers
19
25
  } from "./chunk-66HGCPBU.js";
@@ -947,6 +953,112 @@ function generateEphemeralReceiptKey() {
947
953
  return { secret: bytesToHex(secretKey), pubkey: bytesToHex(publicKey) };
948
954
  }
949
955
 
956
+ // src/lib/wallet-agent/keypair.ts
957
+ import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
958
+ var PRIVKEY_HEX_RE = /^[0-9a-f]{64}$/i;
959
+ function derivePubkeyFromPrivkey(privkey) {
960
+ if (!PRIVKEY_HEX_RE.test(privkey)) {
961
+ throw new DvmError(
962
+ "invalid_privkey",
963
+ "Privkey must be 64 hex characters (32 bytes).",
964
+ "Provide a valid secp256k1 private key as a 64-char hex string."
965
+ );
966
+ }
967
+ const bytes = hexToBytes2(privkey);
968
+ if (!secp256k12.utils.isValidSecretKey(bytes)) {
969
+ throw new DvmError(
970
+ "invalid_privkey",
971
+ "Privkey is not a valid secp256k1 scalar (zero or out of curve order).",
972
+ "Generate a fresh key with: dvm wallet init"
973
+ );
974
+ }
975
+ const pub = secp256k12.getPublicKey(bytes);
976
+ return bytesToHex2(pub);
977
+ }
978
+ function bytesToHex2(bytes) {
979
+ return Buffer.from(bytes).toString("hex");
980
+ }
981
+ function hexToBytes2(hex) {
982
+ return Uint8Array.from(Buffer.from(hex, "hex"));
983
+ }
984
+
985
+ // src/lib/wallet-agent/sign.ts
986
+ import { schnorr as schnorr2 } from "@noble/curves/secp256k1.js";
987
+ var PUBKEY_COMPRESSED_HEX_RE = /^0[23][0-9a-f]{64}$/i;
988
+ var PUBKEY_XONLY_HEX_RE = /^[0-9a-f]{64}$/i;
989
+ var SIG_HEX_RE = /^[0-9a-f]{128}$/i;
990
+ function signChallenge(privkeyHex, challenge) {
991
+ if (!PRIVKEY_HEX_RE.test(privkeyHex)) {
992
+ throw new DvmError(
993
+ "invalid_privkey",
994
+ "Privkey must be 64 hex characters (32 bytes).",
995
+ "Provide a valid secp256k1 private key as a 64-char hex string."
996
+ );
997
+ }
998
+ if (challenge.length !== 32) {
999
+ throw new DvmError(
1000
+ "invalid_challenge",
1001
+ `Challenge must be exactly 32 bytes; got ${challenge.length}.`,
1002
+ "Pass the SHA-256 digest output (32 bytes)."
1003
+ );
1004
+ }
1005
+ const sig = schnorr2.sign(challenge, hexToBytes3(privkeyHex));
1006
+ return bytesToHex3(sig);
1007
+ }
1008
+ function verifyChallenge(pubkeyHex, challenge, sigHex) {
1009
+ if (!SIG_HEX_RE.test(sigHex)) return false;
1010
+ if (challenge.length !== 32) return false;
1011
+ let xonly;
1012
+ if (PUBKEY_COMPRESSED_HEX_RE.test(pubkeyHex)) {
1013
+ xonly = hexToBytes3(pubkeyHex.slice(2));
1014
+ } else if (PUBKEY_XONLY_HEX_RE.test(pubkeyHex)) {
1015
+ xonly = hexToBytes3(pubkeyHex);
1016
+ } else {
1017
+ return false;
1018
+ }
1019
+ try {
1020
+ return schnorr2.verify(hexToBytes3(sigHex), challenge, xonly);
1021
+ } catch {
1022
+ return false;
1023
+ }
1024
+ }
1025
+ function hexToBytes3(hex) {
1026
+ return Uint8Array.from(Buffer.from(hex, "hex"));
1027
+ }
1028
+ function bytesToHex3(bytes) {
1029
+ return Buffer.from(bytes).toString("hex");
1030
+ }
1031
+
1032
+ // src/lib/cashu/admin-auth.ts
1033
+ import { randomBytes } from "crypto";
1034
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1035
+ var ADMIN_AUTH_NONCE_TTL_SECONDS = 300;
1036
+ var ADMIN_AUTH_CLOCK_SKEW_SECONDS = 30;
1037
+ var ADMIN_STATE_UNAVAILABLE = "admin_state_unavailable";
1038
+ function buildAdminChallenge(args) {
1039
+ const msg = `dvmkit-admin:${args.method}:${args.path}:${args.dvmId}:${args.nonceHex}:${args.unixSeconds}`;
1040
+ return sha2562(new TextEncoder().encode(msg));
1041
+ }
1042
+ function buildAdminAuthHeader(args) {
1043
+ const nowMs = args.now ? args.now() : Date.now();
1044
+ const unixSeconds = Math.floor(nowMs / 1e3);
1045
+ const nonceBytes = args.randomNonce ? args.randomNonce() : Uint8Array.from(randomBytes(16));
1046
+ const nonceHex = Buffer.from(nonceBytes).toString("hex");
1047
+ const challenge = buildAdminChallenge({
1048
+ method: args.method,
1049
+ path: args.path,
1050
+ dvmId: args.dvmId,
1051
+ nonceHex,
1052
+ unixSeconds
1053
+ });
1054
+ const sigHex = signChallenge(args.privkeyHex, challenge);
1055
+ return {
1056
+ header: `P2PK ${nonceHex}.${unixSeconds}.${sigHex}`,
1057
+ nonceHex,
1058
+ unixSeconds
1059
+ };
1060
+ }
1061
+
950
1062
  // src/lib/builder-identity.ts
951
1063
  import {
952
1064
  chmodSync as chmodSync3,
@@ -958,8 +1070,8 @@ import {
958
1070
  unlinkSync as unlinkSync4,
959
1071
  writeFileSync as writeFileSync5
960
1072
  } from "fs";
961
- import { schnorr as schnorr2 } from "@noble/curves/secp256k1.js";
962
- import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
1073
+ import { schnorr as schnorr3 } from "@noble/curves/secp256k1.js";
1074
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
963
1075
 
964
1076
  // src/lib/builder-store.ts
965
1077
  import {
@@ -1064,8 +1176,8 @@ function migrateV1Store(parsed) {
1064
1176
 
1065
1177
  // src/lib/builder-identity.ts
1066
1178
  function generateIdentity() {
1067
- const { secretKey, publicKey } = schnorr2.keygen();
1068
- return { pubkey: bytesToHex2(publicKey), secret: bytesToHex2(secretKey) };
1179
+ const { secretKey, publicKey } = schnorr3.keygen();
1180
+ return { pubkey: bytesToHex4(publicKey), secret: bytesToHex4(secretKey) };
1069
1181
  }
1070
1182
  function loadIdentitySecret() {
1071
1183
  if (!existsSync5(BUILDER_KEY_FILE)) return null;
@@ -1108,7 +1220,7 @@ function writeIdentity(keypair, opts = {}) {
1108
1220
  setIdentityPubkey(keypair.pubkey);
1109
1221
  }
1110
1222
  function hashCapabilities(capabilities) {
1111
- return bytesToHex2(sha2562(canonicaliseForSigning(capabilities)));
1223
+ return bytesToHex4(sha2563(canonicaliseForSigning(capabilities)));
1112
1224
  }
1113
1225
  function buildAttestation(args) {
1114
1226
  return {
@@ -1121,14 +1233,14 @@ function buildAttestation(args) {
1121
1233
  };
1122
1234
  }
1123
1235
  function signAttestation(payload, secretHex) {
1124
- const secretBytes = hexToBytes2(secretHex);
1236
+ const secretBytes = hexToBytes4(secretHex);
1125
1237
  const canonicalBytes = canonicaliseForSigning(payload);
1126
- return bytesToHex2(schnorr2.sign(canonicalBytes, secretBytes));
1238
+ return bytesToHex4(schnorr3.sign(canonicalBytes, secretBytes));
1127
1239
  }
1128
1240
  function verifyAttestation(payload, signatureHex, pubkeyHex) {
1129
1241
  try {
1130
1242
  const canonicalBytes = canonicaliseForSigning(payload);
1131
- return schnorr2.verify(hexToBytes2(signatureHex), canonicalBytes, hexToBytes2(pubkeyHex));
1243
+ return schnorr3.verify(hexToBytes4(signatureHex), canonicalBytes, hexToBytes4(pubkeyHex));
1132
1244
  } catch {
1133
1245
  return false;
1134
1246
  }
@@ -1151,12 +1263,12 @@ function warnAndTightenLooseKeyMode() {
1151
1263
  } catch {
1152
1264
  }
1153
1265
  }
1154
- function bytesToHex2(bytes) {
1266
+ function bytesToHex4(bytes) {
1155
1267
  let s = "";
1156
1268
  for (const b of bytes) s += b.toString(16).padStart(2, "0");
1157
1269
  return s;
1158
1270
  }
1159
- function hexToBytes2(hex) {
1271
+ function hexToBytes4(hex) {
1160
1272
  if (hex.length % 2 !== 0) {
1161
1273
  throw new Error(`hex string has odd length: ${String(hex.length)}`);
1162
1274
  }
@@ -1167,82 +1279,6 @@ function hexToBytes2(hex) {
1167
1279
  return out;
1168
1280
  }
1169
1281
 
1170
- // src/lib/receipt.ts
1171
- import { schnorr as schnorr3 } from "@noble/curves/secp256k1.js";
1172
- import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
1173
- import { bytesToHex as bytesToHex3, hexToBytes as hexToBytes3 } from "@noble/hashes/utils.js";
1174
- function computeResultHash(summary, artifactContents) {
1175
- const artifactHashes = artifactContents.map(
1176
- (content) => bytesToHex3(sha2563(canonicaliseForSigning(content)))
1177
- );
1178
- return bytesToHex3(
1179
- sha2563(
1180
- canonicaliseForSigning({
1181
- summary: summary ?? null,
1182
- artifact_hashes: artifactHashes
1183
- })
1184
- )
1185
- );
1186
- }
1187
- function signReceipt(unsigned, secretHex) {
1188
- const bytes = canonicaliseForSigning(unsigned);
1189
- const signature = bytesToHex3(schnorr3.sign(bytes, hexToBytes3(secretHex)));
1190
- return { ...unsigned, signature };
1191
- }
1192
- function verifyReceipt(receipt) {
1193
- try {
1194
- const { signature, ...unsigned } = receipt;
1195
- const bytes = canonicaliseForSigning(unsigned);
1196
- return schnorr3.verify(hexToBytes3(signature), bytes, hexToBytes3(receipt.receipt_pubkey));
1197
- } catch {
1198
- return false;
1199
- }
1200
- }
1201
- function isSignedJobReceipt(value) {
1202
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1203
- const r = value;
1204
- const paid = r.paid;
1205
- return r.v === 1 && typeof r.job_id === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.capability === "string" && (r.outcome === "completed" || r.outcome === "failed" || r.outcome === "cancelled") && typeof r.seq === "number" && typeof r.issued_at === "number" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string" && !!paid && typeof paid === "object" && !Array.isArray(paid) && typeof paid.msats === "number";
1206
- }
1207
- function signDrainReceipt(unsigned, secretHex) {
1208
- const bytes = canonicaliseForSigning(unsigned);
1209
- const signature = bytesToHex3(schnorr3.sign(bytes, hexToBytes3(secretHex)));
1210
- return { ...unsigned, signature };
1211
- }
1212
- function signFundingReceipt(unsigned, secretHex) {
1213
- const bytes = canonicaliseForSigning(unsigned);
1214
- const signature = bytesToHex3(schnorr3.sign(bytes, hexToBytes3(secretHex)));
1215
- return { ...unsigned, signature };
1216
- }
1217
- function isFundingReceipt(value) {
1218
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1219
- const r = value;
1220
- return r.v === 1 && r.kind === "credit_funding" && typeof r.credit_id === "string" && typeof r.fund_id === "string" && typeof r.funded_micro === "number" && typeof r.balance_after_micro === "number" && typeof r.ledger_seq === "number" && typeof r.issued_at === "number" && typeof r.caller_pubkey === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string";
1221
- }
1222
- function verifyFundingReceipt(receipt) {
1223
- try {
1224
- const { signature, ...unsigned } = receipt;
1225
- const bytes = canonicaliseForSigning(unsigned);
1226
- return schnorr3.verify(hexToBytes3(signature), bytes, hexToBytes3(receipt.receipt_pubkey));
1227
- } catch {
1228
- return false;
1229
- }
1230
- }
1231
- function isDrainReceipt(value) {
1232
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1233
- const r = value;
1234
- return r.v === 1 && r.kind === "credit_drain" && typeof r.credit_id === "string" && typeof r.drain_id === "string" && (r.event === "requested" || r.event === "parked" || r.event === "picked_up" || r.event === "sent" || r.event === "released") && typeof r.method === "string" && typeof r.amount_micro === "number" && typeof r.issued_at === "number" && typeof r.caller_pubkey === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string";
1235
- }
1236
- function verifyDrainReceipt(receipt) {
1237
- try {
1238
- const { signature, ...unsigned } = receipt;
1239
- const bytes = canonicaliseForSigning(unsigned);
1240
- return schnorr3.verify(hexToBytes3(signature), bytes, hexToBytes3(receipt.receipt_pubkey));
1241
- } catch {
1242
- return false;
1243
- }
1244
- }
1245
-
1246
1282
  // src/lib/receipt-verify.ts
1247
1283
  function attestedDvmIdentity(builder) {
1248
1284
  const builderPubkey = authenticatedBuilderPubkey(builder);
@@ -1532,112 +1568,6 @@ function parseTraceparent(header) {
1532
1568
  return { traceId, parentSpanId, flags: parseInt(flagsHex, 16) };
1533
1569
  }
1534
1570
 
1535
- // src/lib/wallet-agent/keypair.ts
1536
- import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
1537
- var PRIVKEY_HEX_RE = /^[0-9a-f]{64}$/i;
1538
- function derivePubkeyFromPrivkey(privkey) {
1539
- if (!PRIVKEY_HEX_RE.test(privkey)) {
1540
- throw new DvmError(
1541
- "invalid_privkey",
1542
- "Privkey must be 64 hex characters (32 bytes).",
1543
- "Provide a valid secp256k1 private key as a 64-char hex string."
1544
- );
1545
- }
1546
- const bytes = hexToBytes4(privkey);
1547
- if (!secp256k12.utils.isValidSecretKey(bytes)) {
1548
- throw new DvmError(
1549
- "invalid_privkey",
1550
- "Privkey is not a valid secp256k1 scalar (zero or out of curve order).",
1551
- "Generate a fresh key with: dvm wallet init"
1552
- );
1553
- }
1554
- const pub = secp256k12.getPublicKey(bytes);
1555
- return bytesToHex4(pub);
1556
- }
1557
- function bytesToHex4(bytes) {
1558
- return Buffer.from(bytes).toString("hex");
1559
- }
1560
- function hexToBytes4(hex) {
1561
- return Uint8Array.from(Buffer.from(hex, "hex"));
1562
- }
1563
-
1564
- // src/lib/wallet-agent/sign.ts
1565
- import { schnorr as schnorr4 } from "@noble/curves/secp256k1.js";
1566
- var PUBKEY_COMPRESSED_HEX_RE = /^0[23][0-9a-f]{64}$/i;
1567
- var PUBKEY_XONLY_HEX_RE = /^[0-9a-f]{64}$/i;
1568
- var SIG_HEX_RE = /^[0-9a-f]{128}$/i;
1569
- function signChallenge(privkeyHex, challenge) {
1570
- if (!PRIVKEY_HEX_RE.test(privkeyHex)) {
1571
- throw new DvmError(
1572
- "invalid_privkey",
1573
- "Privkey must be 64 hex characters (32 bytes).",
1574
- "Provide a valid secp256k1 private key as a 64-char hex string."
1575
- );
1576
- }
1577
- if (challenge.length !== 32) {
1578
- throw new DvmError(
1579
- "invalid_challenge",
1580
- `Challenge must be exactly 32 bytes; got ${challenge.length}.`,
1581
- "Pass the SHA-256 digest output (32 bytes)."
1582
- );
1583
- }
1584
- const sig = schnorr4.sign(challenge, hexToBytes5(privkeyHex));
1585
- return bytesToHex5(sig);
1586
- }
1587
- function verifyChallenge(pubkeyHex, challenge, sigHex) {
1588
- if (!SIG_HEX_RE.test(sigHex)) return false;
1589
- if (challenge.length !== 32) return false;
1590
- let xonly;
1591
- if (PUBKEY_COMPRESSED_HEX_RE.test(pubkeyHex)) {
1592
- xonly = hexToBytes5(pubkeyHex.slice(2));
1593
- } else if (PUBKEY_XONLY_HEX_RE.test(pubkeyHex)) {
1594
- xonly = hexToBytes5(pubkeyHex);
1595
- } else {
1596
- return false;
1597
- }
1598
- try {
1599
- return schnorr4.verify(hexToBytes5(sigHex), challenge, xonly);
1600
- } catch {
1601
- return false;
1602
- }
1603
- }
1604
- function hexToBytes5(hex) {
1605
- return Uint8Array.from(Buffer.from(hex, "hex"));
1606
- }
1607
- function bytesToHex5(bytes) {
1608
- return Buffer.from(bytes).toString("hex");
1609
- }
1610
-
1611
- // src/lib/cashu/admin-auth.ts
1612
- import { randomBytes } from "crypto";
1613
- import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
1614
- var ADMIN_AUTH_NONCE_TTL_SECONDS = 300;
1615
- var ADMIN_AUTH_CLOCK_SKEW_SECONDS = 30;
1616
- var ADMIN_STATE_UNAVAILABLE = "admin_state_unavailable";
1617
- function buildAdminChallenge(args) {
1618
- const msg = `dvmkit-admin:${args.method}:${args.path}:${args.dvmId}:${args.nonceHex}:${args.unixSeconds}`;
1619
- return sha2564(new TextEncoder().encode(msg));
1620
- }
1621
- function buildAdminAuthHeader(args) {
1622
- const nowMs = args.now ? args.now() : Date.now();
1623
- const unixSeconds = Math.floor(nowMs / 1e3);
1624
- const nonceBytes = args.randomNonce ? args.randomNonce() : Uint8Array.from(randomBytes(16));
1625
- const nonceHex = Buffer.from(nonceBytes).toString("hex");
1626
- const challenge = buildAdminChallenge({
1627
- method: args.method,
1628
- path: args.path,
1629
- dvmId: args.dvmId,
1630
- nonceHex,
1631
- unixSeconds
1632
- });
1633
- const sigHex = signChallenge(args.privkeyHex, challenge);
1634
- return {
1635
- header: `P2PK ${nonceHex}.${unixSeconds}.${sigHex}`,
1636
- nonceHex,
1637
- unixSeconds
1638
- };
1639
- }
1640
-
1641
1571
  // src/lib/monotonic-clock.ts
1642
1572
  function createMonotonicClock() {
1643
1573
  let anchorWallMs = Date.now();
@@ -1732,6 +1662,14 @@ export {
1732
1662
  receiptPubkeyFromSecret,
1733
1663
  deriveReceiptKeypair,
1734
1664
  generateEphemeralReceiptKey,
1665
+ PRIVKEY_HEX_RE,
1666
+ derivePubkeyFromPrivkey,
1667
+ verifyChallenge,
1668
+ ADMIN_AUTH_NONCE_TTL_SECONDS,
1669
+ ADMIN_AUTH_CLOCK_SKEW_SECONDS,
1670
+ ADMIN_STATE_UNAVAILABLE,
1671
+ buildAdminChallenge,
1672
+ buildAdminAuthHeader,
1735
1673
  generateIdentity,
1736
1674
  loadIdentitySecret,
1737
1675
  writeIdentity,
@@ -1739,16 +1677,6 @@ export {
1739
1677
  buildAttestation,
1740
1678
  signAttestation,
1741
1679
  verifyAttestation,
1742
- computeResultHash,
1743
- signReceipt,
1744
- verifyReceipt,
1745
- isSignedJobReceipt,
1746
- signDrainReceipt,
1747
- signFundingReceipt,
1748
- isFundingReceipt,
1749
- verifyFundingReceipt,
1750
- isDrainReceipt,
1751
- verifyDrainReceipt,
1752
1680
  attestedDvmIdentity,
1753
1681
  authenticatedBuilderPubkey,
1754
1682
  verifyJobReceipt,
@@ -1765,13 +1693,5 @@ export {
1765
1693
  receiptFailureDetail,
1766
1694
  isPublicRequestId,
1767
1695
  parseTraceparent,
1768
- PRIVKEY_HEX_RE,
1769
- derivePubkeyFromPrivkey,
1770
- verifyChallenge,
1771
- ADMIN_AUTH_NONCE_TTL_SECONDS,
1772
- ADMIN_AUTH_CLOCK_SKEW_SECONDS,
1773
- ADMIN_STATE_UNAVAILABLE,
1774
- buildAdminChallenge,
1775
- buildAdminAuthHeader,
1776
1696
  createMonotonicClock
1777
1697
  };
@@ -2,6 +2,9 @@ import {
2
2
  BTC_RATE_FILE,
3
3
  ensureConfigSubdir
4
4
  } from "./chunk-CZULM42S.js";
5
+ import {
6
+ canonicaliseForSigning
7
+ } from "./chunk-OFVV37XC.js";
5
8
  import {
6
9
  formatFiat
7
10
  } from "./chunk-AT6V3SY7.js";
@@ -232,6 +235,82 @@ async function fetchFromApi() {
232
235
  return rate;
233
236
  }
234
237
 
238
+ // src/lib/receipt.ts
239
+ import { schnorr } from "@noble/curves/secp256k1.js";
240
+ import { sha256 } from "@noble/hashes/sha2.js";
241
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
242
+ function computeResultHash(summary, artifactContents) {
243
+ const artifactHashes = artifactContents.map(
244
+ (content) => bytesToHex(sha256(canonicaliseForSigning(content)))
245
+ );
246
+ return bytesToHex(
247
+ sha256(
248
+ canonicaliseForSigning({
249
+ summary: summary ?? null,
250
+ artifact_hashes: artifactHashes
251
+ })
252
+ )
253
+ );
254
+ }
255
+ function signReceipt(unsigned, secretHex) {
256
+ const bytes = canonicaliseForSigning(unsigned);
257
+ const signature = bytesToHex(schnorr.sign(bytes, hexToBytes(secretHex)));
258
+ return { ...unsigned, signature };
259
+ }
260
+ function verifyReceipt(receipt) {
261
+ try {
262
+ const { signature, ...unsigned } = receipt;
263
+ const bytes = canonicaliseForSigning(unsigned);
264
+ return schnorr.verify(hexToBytes(signature), bytes, hexToBytes(receipt.receipt_pubkey));
265
+ } catch {
266
+ return false;
267
+ }
268
+ }
269
+ function isSignedJobReceipt(value) {
270
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
271
+ const r = value;
272
+ const paid = r.paid;
273
+ return r.v === 1 && typeof r.job_id === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.capability === "string" && (r.outcome === "completed" || r.outcome === "failed" || r.outcome === "cancelled") && typeof r.seq === "number" && typeof r.issued_at === "number" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string" && !!paid && typeof paid === "object" && !Array.isArray(paid) && typeof paid.msats === "number";
274
+ }
275
+ function signDrainReceipt(unsigned, secretHex) {
276
+ const bytes = canonicaliseForSigning(unsigned);
277
+ const signature = bytesToHex(schnorr.sign(bytes, hexToBytes(secretHex)));
278
+ return { ...unsigned, signature };
279
+ }
280
+ function signFundingReceipt(unsigned, secretHex) {
281
+ const bytes = canonicaliseForSigning(unsigned);
282
+ const signature = bytesToHex(schnorr.sign(bytes, hexToBytes(secretHex)));
283
+ return { ...unsigned, signature };
284
+ }
285
+ function isFundingReceipt(value) {
286
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
287
+ const r = value;
288
+ return r.v === 1 && r.kind === "credit_funding" && typeof r.credit_id === "string" && typeof r.fund_id === "string" && typeof r.funded_micro === "number" && typeof r.balance_after_micro === "number" && typeof r.ledger_seq === "number" && typeof r.issued_at === "number" && typeof r.caller_pubkey === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string";
289
+ }
290
+ function verifyFundingReceipt(receipt) {
291
+ try {
292
+ const { signature, ...unsigned } = receipt;
293
+ const bytes = canonicaliseForSigning(unsigned);
294
+ return schnorr.verify(hexToBytes(signature), bytes, hexToBytes(receipt.receipt_pubkey));
295
+ } catch {
296
+ return false;
297
+ }
298
+ }
299
+ function isDrainReceipt(value) {
300
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
301
+ const r = value;
302
+ return r.v === 1 && r.kind === "credit_drain" && typeof r.credit_id === "string" && typeof r.drain_id === "string" && (r.event === "requested" || r.event === "parked" || r.event === "picked_up" || r.event === "sent" || r.event === "released") && typeof r.method === "string" && typeof r.amount_micro === "number" && typeof r.issued_at === "number" && typeof r.caller_pubkey === "string" && typeof r.dvm_id === "string" && typeof r.dvm === "string" && typeof r.receipt_pubkey === "string" && typeof r.signature === "string";
303
+ }
304
+ function verifyDrainReceipt(receipt) {
305
+ try {
306
+ const { signature, ...unsigned } = receipt;
307
+ const bytes = canonicaliseForSigning(unsigned);
308
+ return schnorr.verify(hexToBytes(signature), bytes, hexToBytes(receipt.receipt_pubkey));
309
+ } catch {
310
+ return false;
311
+ }
312
+ }
313
+
235
314
  export {
236
315
  IMPLICIT_CREDIT_TTL_MS,
237
316
  COINGECKO_SIMPLE_PRICE_URL,
@@ -254,5 +333,15 @@ export {
254
333
  fetchBtcUsdRate,
255
334
  getLastKnownBtcRate,
256
335
  formatStaleness,
257
- formatAmountBestEffort
336
+ formatAmountBestEffort,
337
+ computeResultHash,
338
+ signReceipt,
339
+ verifyReceipt,
340
+ isSignedJobReceipt,
341
+ signDrainReceipt,
342
+ signFundingReceipt,
343
+ isFundingReceipt,
344
+ verifyFundingReceipt,
345
+ isDrainReceipt,
346
+ verifyDrainReceipt
258
347
  };
@@ -10,39 +10,6 @@ import {
10
10
  projectSpanRow
11
11
  } from "./chunk-ETXDTUJO.js";
12
12
 
13
- // src/sdk/step-cache.ts
14
- var StepCache = class _StepCache {
15
- cache = /* @__PURE__ */ new Map();
16
- has(id) {
17
- return this.cache.has(id);
18
- }
19
- get(id) {
20
- return this.getRecord(id).value;
21
- }
22
- getRecord(id) {
23
- const record = this.cache.get(id);
24
- if (record === void 0) throw new Error(`StepCache: no cached result for step "${id}"`);
25
- return record;
26
- }
27
- set(id, value, costs) {
28
- this.cache.set(id, {
29
- id,
30
- value,
31
- ...costs !== void 0 && costs.length > 0 ? { costs: costs.map(({ amount, currency }) => ({ amount, currency })) } : {}
32
- });
33
- }
34
- serialize() {
35
- return [...this.cache.values()];
36
- }
37
- static deserialize(records) {
38
- const cache = new _StepCache();
39
- for (const { id, value, costs } of records) {
40
- cache.set(id, value, costs);
41
- }
42
- return cache;
43
- }
44
- };
45
-
46
13
  // src/sdk/logger.ts
47
14
  function createConsoleLogger(_jobId) {
48
15
  return {
@@ -373,15 +340,15 @@ async function withSpan(opts, fn) {
373
340
 
374
341
  // src/observability/datasets.ts
375
342
  var SPANS_DATASETS = [
376
- { name: "platform", retentionDays: 90 },
377
- { name: "cashu", retentionDays: 90 },
378
- { name: "lightning", retentionDays: 90 },
379
- { name: "stripe", retentionDays: 90 },
380
- { name: "x402", retentionDays: 90 },
381
- { name: "tempo", retentionDays: 90 },
382
- { name: "isolate", retentionDays: 90 },
383
- { name: "audit", retentionDays: 365 },
384
- { name: "cron", retentionDays: 30 }
343
+ { name: "platform", retentionDays: 730 },
344
+ { name: "cashu", retentionDays: 730 },
345
+ { name: "lightning", retentionDays: 730 },
346
+ { name: "stripe", retentionDays: 730 },
347
+ { name: "x402", retentionDays: 730 },
348
+ { name: "tempo", retentionDays: 730 },
349
+ { name: "isolate", retentionDays: 730 },
350
+ { name: "audit", retentionDays: 730 },
351
+ { name: "cron", retentionDays: 730 }
385
352
  ];
386
353
  var DATASET_NAMES = new Set(SPANS_DATASETS.map((d) => d.name));
387
354
 
@@ -485,7 +452,6 @@ function buildNoopLoggers() {
485
452
  }
486
453
 
487
454
  export {
488
- StepCache,
489
455
  createConsoleLogger,
490
456
  createStdoutLogger,
491
457
  createNoopLogger,