@lemmaoracle/x402 0.1.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 (126) hide show
  1. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-1775996174982.json +34 -0
  2. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-1775996423983.json +51 -0
  3. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-1775996907850.json +51 -0
  4. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-latest.json +51 -0
  5. package/cache/DeployPaymentVerifier.s.sol/10143/run-1775996174982.json +7 -0
  6. package/cache/DeployPaymentVerifier.s.sol/10143/run-1775996423983.json +7 -0
  7. package/cache/DeployPaymentVerifier.s.sol/10143/run-1775996907850.json +7 -0
  8. package/cache/DeployPaymentVerifier.s.sol/10143/run-latest.json +7 -0
  9. package/cache/solidity-files-cache.json +1 -0
  10. package/circuits/README.md +78 -0
  11. package/circuits/payment-comprehensive.test.mjs +272 -0
  12. package/circuits/payment.circom +89 -0
  13. package/circuits/payment.test.mjs +173 -0
  14. package/dist/index.d.ts +48 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +83 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/proof-generator.d.ts +26 -0
  19. package/dist/proof-generator.d.ts.map +1 -0
  20. package/dist/proof-generator.js +154 -0
  21. package/dist/proof-generator.js.map +1 -0
  22. package/dist/proof-generator.test.d.ts +7 -0
  23. package/dist/proof-generator.test.d.ts.map +1 -0
  24. package/dist/proof-generator.test.js +121 -0
  25. package/dist/proof-generator.test.js.map +1 -0
  26. package/dist/transaction-watcher.d.ts +42 -0
  27. package/dist/transaction-watcher.d.ts.map +1 -0
  28. package/dist/transaction-watcher.js +88 -0
  29. package/dist/transaction-watcher.js.map +1 -0
  30. package/dist/transaction-watcher.test.d.ts +7 -0
  31. package/dist/transaction-watcher.test.d.ts.map +1 -0
  32. package/dist/transaction-watcher.test.js +111 -0
  33. package/dist/transaction-watcher.test.js.map +1 -0
  34. package/dist/types.d.ts +76 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +2 -0
  37. package/dist/types.js.map +1 -0
  38. package/foundry.lock +11 -0
  39. package/foundry.toml +16 -0
  40. package/lib/forge-std/.gitattributes +1 -0
  41. package/lib/forge-std/.github/CODEOWNERS +1 -0
  42. package/lib/forge-std/.github/dependabot.yml +6 -0
  43. package/lib/forge-std/.github/workflows/ci.yml +161 -0
  44. package/lib/forge-std/.github/workflows/sync.yml +36 -0
  45. package/lib/forge-std/CONTRIBUTING.md +193 -0
  46. package/lib/forge-std/LICENSE-APACHE +203 -0
  47. package/lib/forge-std/LICENSE-MIT +25 -0
  48. package/lib/forge-std/README.md +314 -0
  49. package/lib/forge-std/RELEASE_CHECKLIST.md +12 -0
  50. package/lib/forge-std/foundry.toml +18 -0
  51. package/lib/forge-std/package.json +16 -0
  52. package/lib/forge-std/scripts/vm.py +636 -0
  53. package/lib/forge-std/src/Base.sol +48 -0
  54. package/lib/forge-std/src/Config.sol +60 -0
  55. package/lib/forge-std/src/LibVariable.sol +477 -0
  56. package/lib/forge-std/src/Script.sol +28 -0
  57. package/lib/forge-std/src/StdAssertions.sol +1300 -0
  58. package/lib/forge-std/src/StdChains.sol +303 -0
  59. package/lib/forge-std/src/StdCheats.sol +825 -0
  60. package/lib/forge-std/src/StdConfig.sol +632 -0
  61. package/lib/forge-std/src/StdConstants.sol +30 -0
  62. package/lib/forge-std/src/StdError.sol +15 -0
  63. package/lib/forge-std/src/StdInvariant.sol +161 -0
  64. package/lib/forge-std/src/StdJson.sol +275 -0
  65. package/lib/forge-std/src/StdMath.sol +47 -0
  66. package/lib/forge-std/src/StdStorage.sol +476 -0
  67. package/lib/forge-std/src/StdStyle.sol +333 -0
  68. package/lib/forge-std/src/StdToml.sol +275 -0
  69. package/lib/forge-std/src/StdUtils.sol +200 -0
  70. package/lib/forge-std/src/Test.sol +32 -0
  71. package/lib/forge-std/src/Vm.sol +2533 -0
  72. package/lib/forge-std/src/console.sol +1551 -0
  73. package/lib/forge-std/src/console2.sol +4 -0
  74. package/lib/forge-std/src/interfaces/IERC1155.sol +105 -0
  75. package/lib/forge-std/src/interfaces/IERC165.sol +12 -0
  76. package/lib/forge-std/src/interfaces/IERC20.sol +43 -0
  77. package/lib/forge-std/src/interfaces/IERC4626.sol +190 -0
  78. package/lib/forge-std/src/interfaces/IERC6909.sol +72 -0
  79. package/lib/forge-std/src/interfaces/IERC721.sol +164 -0
  80. package/lib/forge-std/src/interfaces/IERC7540.sol +145 -0
  81. package/lib/forge-std/src/interfaces/IERC7575.sol +241 -0
  82. package/lib/forge-std/src/interfaces/IMulticall3.sol +68 -0
  83. package/lib/forge-std/src/safeconsole.sol +13248 -0
  84. package/lib/forge-std/test/CommonBase.t.sol +44 -0
  85. package/lib/forge-std/test/Config.t.sol +381 -0
  86. package/lib/forge-std/test/LibVariable.t.sol +452 -0
  87. package/lib/forge-std/test/StdAssertions.t.sol +141 -0
  88. package/lib/forge-std/test/StdChains.t.sol +227 -0
  89. package/lib/forge-std/test/StdCheats.t.sol +638 -0
  90. package/lib/forge-std/test/StdConstants.t.sol +38 -0
  91. package/lib/forge-std/test/StdError.t.sol +119 -0
  92. package/lib/forge-std/test/StdJson.t.sol +49 -0
  93. package/lib/forge-std/test/StdMath.t.sol +202 -0
  94. package/lib/forge-std/test/StdStorage.t.sol +532 -0
  95. package/lib/forge-std/test/StdStyle.t.sol +110 -0
  96. package/lib/forge-std/test/StdToml.t.sol +49 -0
  97. package/lib/forge-std/test/StdUtils.t.sol +342 -0
  98. package/lib/forge-std/test/Vm.t.sol +18 -0
  99. package/lib/forge-std/test/compilation/CompilationScript.sol +8 -0
  100. package/lib/forge-std/test/compilation/CompilationScriptBase.sol +8 -0
  101. package/lib/forge-std/test/compilation/CompilationTest.sol +8 -0
  102. package/lib/forge-std/test/compilation/CompilationTestBase.sol +8 -0
  103. package/lib/forge-std/test/fixtures/broadcast.log.json +187 -0
  104. package/lib/forge-std/test/fixtures/config.toml +81 -0
  105. package/lib/forge-std/test/fixtures/test.json +8 -0
  106. package/lib/forge-std/test/fixtures/test.toml +6 -0
  107. package/package.json +55 -0
  108. package/package.json.backup +55 -0
  109. package/scripts/DeployPaymentVerifier.s.sol +18 -0
  110. package/scripts/build.sh +61 -0
  111. package/scripts/deploy.sh +65 -0
  112. package/scripts/fix-verifier.mjs +64 -0
  113. package/scripts/register-circuit.ts +213 -0
  114. package/scripts/test-with-circuit.mjs +88 -0
  115. package/src/index.ts +115 -0
  116. package/src/proof-generator.test.ts +139 -0
  117. package/src/proof-generator.ts +220 -0
  118. package/src/transaction-watcher.test.ts +153 -0
  119. package/src/transaction-watcher.ts +154 -0
  120. package/src/types.ts +110 -0
  121. package/tsconfig.json +14 -0
  122. package/tsconfig.tsbuildinfo +1 -0
  123. package/vitest.config.ts +18 -0
  124. package/workers/x402-facilitator/src/index.ts +582 -0
  125. package/workers/x402-facilitator/src/x402-env.d.ts +25 -0
  126. package/workers/x402-facilitator/wrangler.toml +19 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * X402 Payment Proof Generator
3
+ *
4
+ * Generates ZK proofs for x402 payment transactions so that
5
+ * Lemma's disclosure.condition API can verify payments without
6
+ * exposing transaction details.
7
+ */
8
+ import { type LemmaClient } from "@lemmaoracle/sdk";
9
+ import type { ProofResult, Config, Transaction, Proof } from "./types.js";
10
+ /**
11
+ * Generates x402 payment proofs using Lemma's prover infrastructure.
12
+ *
13
+ * Usage:
14
+ * const generator = new X402ProofGenerator(config, lemmaClient);
15
+ * const result = await generator.generateProof(txHash);
16
+ */
17
+ declare const createProofGenerator: (config: Config, lemmaClient: LemmaClient) => Readonly<{
18
+ generateProof: (txHash: `0x${string}`) => Promise<ProofResult>;
19
+ toFieldElements: (payment: Transaction, config: Config) => Readonly<{
20
+ witness: Record<string, string>;
21
+ publicInputs: string[];
22
+ }>;
23
+ }>;
24
+ export type { ProofResult, Config, Proof, Transaction, };
25
+ export { createProofGenerator };
26
+ //# sourceMappingURL=proof-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-generator.d.ts","sourceRoot":"","sources":["../src/proof-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,KAAK,EACV,WAAW,EACX,MAAM,EACN,WAAW,EACX,KAAK,EACN,MAAM,YAAY,CAAC;AAmBpB;;;;;;GAMG;AACH,QAAA,MAAM,oBAAoB,GACxB,QAAQ,MAAM,EACd,aAAa,WAAW,KACvB,QAAQ,CAAC;IACV,aAAa,EAAE,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/D,eAAe,EAAE,CACf,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,KACX,QAAQ,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CAC5E,CAqEA,CAAC;AA4FF,YAAY,EACV,WAAW,EACX,MAAM,EACN,KAAK,EACL,WAAW,GACZ,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * X402 Payment Proof Generator
3
+ *
4
+ * Generates ZK proofs for x402 payment transactions so that
5
+ * Lemma's disclosure.condition API can verify payments without
6
+ * exposing transaction details.
7
+ */
8
+ import { createPublicClient, http } from "viem";
9
+ import { prover } from "@lemmaoracle/sdk";
10
+ import * as R from "ramda";
11
+ // ---------------------------------------------------------------------------
12
+ // Constants
13
+ // ---------------------------------------------------------------------------
14
+ /** Default IPFS gateway if not specified in config */
15
+ const _DEFAULT_IPFS_GATEWAY = "https://ipfs.io/ipfs/";
16
+ /** Poseidon hash function for field element hashing */
17
+ const toFieldElement = (value) => BigInt(value) < 0n
18
+ ? String(BigInt(value) % 21888242871839275222246405745257275088548364400416034343698204186575808495617n)
19
+ : value;
20
+ // ---------------------------------------------------------------------------
21
+ // Proof Generator Class
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * Generates x402 payment proofs using Lemma's prover infrastructure.
25
+ *
26
+ * Usage:
27
+ * const generator = new X402ProofGenerator(config, lemmaClient);
28
+ * const result = await generator.generateProof(txHash);
29
+ */
30
+ const createProofGenerator = (config, lemmaClient) => {
31
+ /** Create public client for transaction inspection */
32
+ const publicClient = createPublicClient({
33
+ transport: http(config.ethereumRpcUrl),
34
+ });
35
+ return {
36
+ /**
37
+ * Generate a payment proof for a given transaction hash.
38
+ * This fetches the transaction details, computes the witness,
39
+ * and generates the ZK proof.
40
+ */
41
+ generateProof: async (txHash) => {
42
+ // Step 1: Fetch transaction details from blockchain
43
+ const payment = await fetchPaymentTransaction(txHash, publicClient);
44
+ // Step 2: Generate proof
45
+ const proofResult = await generateZKProof(lemmaClient, payment, config);
46
+ return R.always({
47
+ payment,
48
+ proof: proofResult,
49
+ })();
50
+ },
51
+ /**
52
+ * Convert payment transaction details to circuit field elements.
53
+ */
54
+ toFieldElements: (payment, cfg) => {
55
+ // Split 256-bit txHash into two 128-bit elements
56
+ const txHashBigInt = BigInt(payment.txHash);
57
+ const upper128 = toFieldElement(String(txHashBigInt >> 128n));
58
+ const lower128 = toFieldElement(String(txHashBigInt & ((1n << 128n) - 1n)));
59
+ // Split 160-bit recipient address
60
+ const recipientBigInt = BigInt(payment.to);
61
+ const recipientLow = toFieldElement(String(recipientBigInt & ((1n << 128n) - 1n)));
62
+ const recipientHigh = toFieldElement(String(recipientBigInt >> 128n));
63
+ // Amount and timestamp
64
+ const amount = toFieldElement(String(payment.amount));
65
+ const timestamp = toFieldElement(String(payment.timestamp));
66
+ const minAmount = toFieldElement(String(cfg.minAmount));
67
+ return R.always({
68
+ witness: {
69
+ txHashPacked_0: lower128,
70
+ txHashPacked_1: upper128,
71
+ recipientLow,
72
+ recipientHigh,
73
+ amount,
74
+ timestamp,
75
+ minAmount,
76
+ },
77
+ publicInputs: [
78
+ // commitment will be computed during proof generation
79
+ toFieldElement(String(cfg.minAmount)), // minAmountPublic
80
+ toFieldElement(String(cfg.maxProofAge)), // timestampMax
81
+ ],
82
+ })();
83
+ },
84
+ };
85
+ };
86
+ // ---------------------------------------------------------------------------
87
+ // Private Helpers
88
+ // ---------------------------------------------------------------------------
89
+ /**
90
+ * Fetch payment transaction details from the blockchain.
91
+ */
92
+ const fetchPaymentTransaction = async (txHash, client) => {
93
+ const txPromise = client.getTransaction({ hash: txHash });
94
+ const receiptPromise = client.getTransactionReceipt({ hash: txHash });
95
+ const blockPromise = client.getBlock({ blockTag: "latest" });
96
+ const [tx, receipt, block] = await Promise.all([
97
+ txPromise,
98
+ receiptPromise,
99
+ blockPromise,
100
+ ]);
101
+ return receipt.status !== "success"
102
+ ? Promise.reject(new Error(`Transaction ${txHash} failed`))
103
+ : client.getBlock({ blockNumber: receipt.blockNumber }).then((blockData) => R.always({
104
+ txHash,
105
+ from: tx.from,
106
+ to: tx.to ?? "0x",
107
+ amount: tx.value + receipt.effectiveGasPrice * receipt.gasUsed,
108
+ timestamp: Number(blockData.timestamp),
109
+ blockNumber: receipt.blockNumber,
110
+ confirmations: Number(block.number - receipt.blockNumber),
111
+ })());
112
+ };
113
+ /**
114
+ * Generate ZK proof for the payment transaction.
115
+ */
116
+ const generateZKProof = async (lemmaClient, payment, config) => {
117
+ // Build witness from payment transaction
118
+ const builder = createProofGenerator(config, lemmaClient);
119
+ const { witness, publicInputs } = builder.toFieldElements(payment, config);
120
+ // Generate proof using Lemma SDK
121
+ const proofResult = await prover.prove(lemmaClient, {
122
+ circuitId: config.circuitId,
123
+ witness,
124
+ });
125
+ // Compute the commitment for public inputs
126
+ const commitment = computeCommitment(witness, publicInputs);
127
+ return R.always({
128
+ proof: proofResult.proof,
129
+ inputs: [commitment, ...publicInputs],
130
+ circuitId: config.circuitId,
131
+ generatedAt: Date.now(),
132
+ })();
133
+ };
134
+ /**
135
+ * Compute the commitment hash for the circuit public inputs.
136
+ */
137
+ const computeCommitment = (witness, _publicInputs) => {
138
+ // The commitment is computed from:
139
+ // poseidon(txHashPacked[0], txHashPacked[1], recipientLow, amount, timestamp, minAmount)
140
+ // This should match the public commitment used in the circuit
141
+ const values = [
142
+ witness.txHashPacked_0,
143
+ witness.txHashPacked_1,
144
+ witness.recipientLow,
145
+ witness.amount,
146
+ witness.timestamp,
147
+ witness.minAmount,
148
+ ];
149
+ // In a real implementation, use poseidon from circomlib
150
+ // For now, we use a simple hash placeholder
151
+ return values.join(",");
152
+ };
153
+ export { createProofGenerator };
154
+ //# sourceMappingURL=proof-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-generator.js","sourceRoot":"","sources":["../src/proof-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAqB,MAAM,MAAM,CAAC;AACnE,OAAO,EAAE,MAAM,EAAoB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,CAAC,MAAM,OAAO,CAAC;AAQ3B,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,sDAAsD;AACtD,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAEtD,uDAAuD;AACvD,MAAM,cAAc,GAAG,CAAC,KAAa,EAAU,EAAE,CAC/C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;IAChB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,8EAA8E,CAAC;IACxG,CAAC,CAAC,KAAK,CAAC;AAEZ,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,oBAAoB,GAAG,CAC3B,MAAc,EACd,WAAwB,EAOvB,EAAE;IACH,sDAAsD;IACtD,MAAM,YAAY,GAAiB,kBAAkB,CAAC;QACpD,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;KACvC,CAAC,CAAC;IAEH,OAAO;QACL;;;;WAIG;QACH,aAAa,EAAE,KAAK,EAAE,MAAqB,EAAwB,EAAE;YACnE,oDAAoD;YACpD,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAEpE,yBAAyB;YACzB,MAAM,WAAW,GAAG,MAAM,eAAe,CACvC,WAAW,EACX,OAAO,EACP,MAAM,CACP,CAAC;YAEF,OAAO,CAAC,CAAC,MAAM,CAAC;gBACd,OAAO;gBACP,KAAK,EAAE,WAAW;aACnB,CAAC,EAAE,CAAC;QACP,CAAC;QAED;;WAEG;QACH,eAAe,EAAE,CACf,OAAoB,EACpB,GAAW,EACX,EAAE;YACF,iDAAiD;YACjD,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC;YAC9D,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YAE5E,kCAAkC;YAClC,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC3C,MAAM,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,eAAe,GAAG,CAAC,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YACnF,MAAM,aAAa,GAAG,cAAc,CAAC,MAAM,CAAC,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC;YAEtE,uBAAuB;YACvB,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YACtD,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;YAExD,OAAO,CAAC,CAAC,MAAM,CAAC;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,QAAQ;oBACxB,cAAc,EAAE,QAAQ;oBACxB,YAAY;oBACZ,aAAa;oBACb,MAAM;oBACN,SAAS;oBACT,SAAS;iBACV;gBACD,YAAY,EAAE;oBACZ,sDAAsD;oBACtD,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,kBAAkB;oBACzD,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,eAAe;iBACzD;aACF,CAAC,EAAE,CAAC;QACP,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;GAEG;AACH,MAAM,uBAAuB,GAAG,KAAK,EACnC,MAAqB,EACrB,MAAoB,EACE,EAAE;IACxB,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1D,MAAM,cAAc,GAAG,MAAM,CAAC,qBAAqB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IAE7D,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7C,SAAS;QACT,cAAc;QACd,YAAY;KACb,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,MAAM,KAAK,SAAS;QACjC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,MAAM,SAAS,CAAC,CAAC;QAC3D,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CACxD,CAAC,SAAS,EAAE,EAAE,CACZ,CAAC,CAAC,MAAM,CAAC;YACP,MAAM;YACN,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,EAAE,EAAE,EAAE,CAAC,EAAE,IAAK,IAAsB;YACpC,MAAM,EAAE,EAAE,CAAC,KAAK,GAAG,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO;YAC9D,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC;YACtC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;SAC1D,CAAC,EAAE,CACP,CAAC;AACR,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAG,KAAK,EAC3B,WAAwB,EACxB,OAAoB,EACpB,MAAc,EACE,EAAE;IAClB,yCAAyC;IACzC,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC1D,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAE3E,iCAAiC;IACjC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE;QAClD,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,OAAO;KACR,CAAC,CAAC;IAEH,2CAA2C;IAC3C,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE5D,OAAO,CAAC,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,MAAM,EAAE,CAAC,UAAU,EAAE,GAAG,YAAY,CAAC;QACrC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE;KACxB,CAAC,EAAE,CAAC;AACP,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,iBAAiB,GAAG,CACxB,OAA+B,EAC/B,aAAuB,EACf,EAAE;IACV,mCAAmC;IACnC,yFAAyF;IACzF,8DAA8D;IAC9D,MAAM,MAAM,GAAG;QACb,OAAO,CAAC,cAAc;QACtB,OAAO,CAAC,cAAc;QACtB,OAAO,CAAC,YAAY;QACpB,OAAO,CAAC,MAAM;QACd,OAAO,CAAC,SAAS;QACjB,OAAO,CAAC,SAAS;KAClB,CAAC;IAEF,wDAAwD;IACxD,4CAA4C;IAC5C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC,CAAC;AASF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for x402 payment proof generator.
3
+ *
4
+ * Test files are exempt from FP rules.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=proof-generator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-generator.test.d.ts","sourceRoot":"","sources":["../src/proof-generator.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Tests for x402 payment proof generator.
3
+ *
4
+ * Test files are exempt from FP rules.
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from "vitest";
7
+ import { createProofGenerator } from "./proof-generator.js";
8
+ // Mock viem
9
+ vi.mock("viem", async () => {
10
+ const actual = await vi.importActual("viem");
11
+ return {
12
+ ...actual,
13
+ createPublicClient: vi.fn(() => ({
14
+ getTransaction: vi.fn().mockResolvedValue({
15
+ hash: "0xabc123",
16
+ from: "0xsender",
17
+ to: "0x2222222222222222222222222222222222222222",
18
+ value: 1000n,
19
+ }),
20
+ getTransactionReceipt: vi.fn().mockResolvedValue({
21
+ status: "success",
22
+ blockNumber: 1000n,
23
+ gasUsed: 21000n,
24
+ effectiveGasPrice: 1000000000n,
25
+ confirmations: 6,
26
+ }),
27
+ getBlock: vi.fn().mockResolvedValue({
28
+ number: 1006n,
29
+ timestamp: 1712000000n,
30
+ }),
31
+ })),
32
+ };
33
+ });
34
+ // Mock Lemma SDK
35
+ vi.mock("@lemmaoracle/sdk", async () => {
36
+ const actual = await vi.importActual("@lemmaoracle/sdk");
37
+ return {
38
+ ...actual,
39
+ prover: {
40
+ prove: vi.fn().mockResolvedValue({
41
+ proof: "mock-proof-base64",
42
+ publicInputs: ["input1", "input2"],
43
+ }),
44
+ },
45
+ createClient: vi.fn().mockReturnValue({
46
+ apiBase: "https://workers.lemma.workers.dev",
47
+ }),
48
+ };
49
+ });
50
+ const mockConfig = {
51
+ payToAddress: "0x2222222222222222222222222222222222222222",
52
+ network: "eip155:84532",
53
+ price: "$0.001",
54
+ ethereumRpcUrl: "https://sepolia.base.org",
55
+ chainId: 84532,
56
+ lemmaApiBase: "https://workers.lemma.workers.dev",
57
+ circuitId: "x402-payment-v1",
58
+ minAmount: 1000n,
59
+ requiredConfirmations: 6,
60
+ maxProofAge: 3600,
61
+ ipfsGateway: "https://ipfs.io/ipfs/",
62
+ };
63
+ const mockLemmaClient = {
64
+ apiBase: "https://workers.lemma.workers.dev",
65
+ };
66
+ describe("X402 Proof Generator", () => {
67
+ beforeEach(() => {
68
+ vi.clearAllMocks();
69
+ });
70
+ it("should create a proof generator", () => {
71
+ const generator = createProofGenerator(mockConfig, mockLemmaClient);
72
+ expect(generator).toBeDefined();
73
+ expect(typeof generator.generateProof).toBe("function");
74
+ expect(typeof generator.toFieldElements).toBe("function");
75
+ });
76
+ it("should convert payment details to field elements", async () => {
77
+ const generator = createProofGenerator(mockConfig, mockLemmaClient);
78
+ const mockPayment = {
79
+ txHash: "0xabc123",
80
+ from: "0x1111111111111111111111111111111111111111",
81
+ to: "0x2222222222222222222222222222222222222222",
82
+ amount: 1000n,
83
+ timestamp: 1712000000,
84
+ blockNumber: 1000n,
85
+ confirmations: 6,
86
+ };
87
+ const result = await generator.toFieldElements(mockPayment, mockConfig);
88
+ expect(result).toBeDefined();
89
+ expect(result.witness).toBeDefined();
90
+ expect(result.publicInputs).toBeDefined();
91
+ expect(result.witness.amount).toBeDefined();
92
+ expect(result.witness.minAmount).toBeDefined();
93
+ });
94
+ it("should handle empty txHash gracefully", async () => {
95
+ const generator = createProofGenerator(mockConfig, mockLemmaClient);
96
+ expect(generator.generateProof).toBeDefined();
97
+ });
98
+ });
99
+ describe("Field Element Conversion", () => {
100
+ it("should convert addresses to field elements", async () => {
101
+ const generator = createProofGenerator(mockConfig, mockLemmaClient);
102
+ const mockPayment = {
103
+ txHash: "0xabc123",
104
+ from: "0x1111111111111111111111111111111111111111",
105
+ to: "0x2222222222222222222222222222222222222222",
106
+ amount: 1000n,
107
+ timestamp: 1712000000,
108
+ blockNumber: 1000n,
109
+ confirmations: 6,
110
+ };
111
+ const { witness } = await generator.toFieldElements(mockPayment, mockConfig);
112
+ // Verify field elements are present and not null
113
+ expect(witness.txHashPacked_0).toBeDefined();
114
+ expect(witness.txHashPacked_1).toBeDefined();
115
+ expect(witness.recipientLow).toBeDefined();
116
+ expect(witness.amount).toBeDefined();
117
+ expect(witness.timestamp).toBeDefined();
118
+ expect(witness.minAmount).toBeDefined();
119
+ });
120
+ });
121
+ //# sourceMappingURL=proof-generator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proof-generator.test.js","sourceRoot":"","sources":["../src/proof-generator.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * X402 Transaction Watcher
3
+ *
4
+ * Monitors the blockchain for x402 payment transactions to the configured
5
+ * recipient address and triggers proof generation when payments are detected.
6
+ */
7
+ import type { Transaction as ViemTransaction, TransactionReceipt } from "viem";
8
+ import type { Config, Transaction } from "./types.js";
9
+ /** Callback invoked when a valid payment is detected */
10
+ type PaymentDetectedCallback = (payment: Transaction) => Promise<void>;
11
+ /** State of the transaction watcher */
12
+ type WatcherState = Readonly<{
13
+ isRunning: boolean;
14
+ lastCheckedBlock: bigint;
15
+ detectedPayments: ReadonlyArray<PaymentDetectedCallback>;
16
+ }>;
17
+ /**
18
+ * Creates a transaction watcher that monitors for payments to the configured address.
19
+ *
20
+ * Uses an immutable state cell (single-element tuple) as a controlled mutable reference.
21
+ */
22
+ declare const createTransactionWatcher: (_config: Config, _publicClient: unknown) => Readonly<{
23
+ start: (_?: undefined) => Promise<void>;
24
+ stop: (_?: undefined) => void;
25
+ onPaymentDetected: (callback: PaymentDetectedCallback) => Promise<void>;
26
+ getState: (_?: undefined) => WatcherState;
27
+ }>;
28
+ /**
29
+ * Validate that a transaction is a valid x402 payment:
30
+ * - Transaction was successful
31
+ * - Sent to the correct recipient
32
+ * - Amount meets the minimum requirement
33
+ * - Has sufficient confirmations
34
+ */
35
+ declare const isValidPayment: (tx: ViemTransaction, receipt: TransactionReceipt, config: Config, currentBlockNumber?: bigint) => boolean;
36
+ /**
37
+ * Extract payment details from transaction and receipt.
38
+ */
39
+ declare const extractPaymentDetails: (tx: ViemTransaction, receipt: TransactionReceipt, currentBlockNumber: bigint) => Transaction;
40
+ export type { PaymentDetectedCallback, WatcherState, };
41
+ export { createTransactionWatcher, isValidPayment, extractPaymentDetails, };
42
+ //# sourceMappingURL=transaction-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-watcher.d.ts","sourceRoot":"","sources":["../src/transaction-watcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,WAAW,IAAI,eAAe,EAC9B,kBAAkB,EACnB,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAMtD,wDAAwD;AACxD,KAAK,uBAAuB,GAAG,CAC7B,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,uCAAuC;AACvC,KAAK,YAAY,GAAG,QAAQ,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;CAC1D,CAAC,CAAC;AAYH;;;;GAIG;AACH,QAAA,MAAM,wBAAwB,GAC5B,SAAS,MAAM,EACf,eAAe,OAAO,KACrB,QAAQ,CAAC;IACV,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAC9B,iBAAiB,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,KAAK,YAAY,CAAC;CAC3C,CAsCA,CAAC;AAMF;;;;;;GAMG;AACH,QAAA,MAAM,cAAc,GAClB,IAAI,eAAe,EACnB,SAAS,kBAAkB,EAC3B,QAAQ,MAAM,EACd,qBAAoB,MAAW,KAC9B,OAUG,CAAC;AAEP;;GAEG;AACH,QAAA,MAAM,qBAAqB,GACzB,IAAI,eAAe,EACnB,SAAS,kBAAkB,EAC3B,oBAAoB,MAAM,KACzB,WAcF,CAAC;AAEF,YAAY,EACV,uBAAuB,EACvB,YAAY,GACb,CAAC;AAEF,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,qBAAqB,GACtB,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * X402 Transaction Watcher
3
+ *
4
+ * Monitors the blockchain for x402 payment transactions to the configured
5
+ * recipient address and triggers proof generation when payments are detected.
6
+ */
7
+ import * as R from "ramda";
8
+ // ---------------------------------------------------------------------------
9
+ // Watcher Implementation
10
+ // ---------------------------------------------------------------------------
11
+ const initialState = {
12
+ isRunning: false,
13
+ lastCheckedBlock: 0n,
14
+ detectedPayments: [],
15
+ };
16
+ /**
17
+ * Creates a transaction watcher that monitors for payments to the configured address.
18
+ *
19
+ * Uses an immutable state cell (single-element tuple) as a controlled mutable reference.
20
+ */
21
+ const createTransactionWatcher = (_config, _publicClient) => {
22
+ const stateCell = { current: initialState };
23
+ const start = (_) => {
24
+ // eslint-disable-next-line functional/no-expression-statements, functional/immutable-data
25
+ stateCell.current = {
26
+ ...stateCell.current,
27
+ isRunning: true,
28
+ lastCheckedBlock: 0n,
29
+ };
30
+ return Promise.resolve();
31
+ };
32
+ const stop = (_) => {
33
+ // eslint-disable-next-line functional/no-expression-statements, functional/immutable-data
34
+ stateCell.current = R.assoc("isRunning", false, stateCell.current);
35
+ };
36
+ const onPaymentDetected = (callback) => {
37
+ // eslint-disable-next-line functional/no-expression-statements, functional/immutable-data
38
+ stateCell.current = {
39
+ ...stateCell.current,
40
+ detectedPayments: R.append(callback, stateCell.current.detectedPayments),
41
+ };
42
+ return Promise.resolve();
43
+ };
44
+ const getState = (_) => stateCell.current;
45
+ return {
46
+ start,
47
+ stop,
48
+ onPaymentDetected,
49
+ getState,
50
+ };
51
+ };
52
+ // ---------------------------------------------------------------------------
53
+ // Utility Functions
54
+ // ---------------------------------------------------------------------------
55
+ /**
56
+ * Validate that a transaction is a valid x402 payment:
57
+ * - Transaction was successful
58
+ * - Sent to the correct recipient
59
+ * - Amount meets the minimum requirement
60
+ * - Has sufficient confirmations
61
+ */
62
+ const isValidPayment = (tx, receipt, config, currentBlockNumber = 0n) => R.allPass([
63
+ R.always(tx.to === config.payToAddress),
64
+ R.always(tx.value >= config.minAmount),
65
+ R.always(receipt.status === "success"),
66
+ R.always(currentBlockNumber > 0n
67
+ ? Number(currentBlockNumber - receipt.blockNumber) >= config.requiredConfirmations
68
+ : true),
69
+ ])();
70
+ /**
71
+ * Extract payment details from transaction and receipt.
72
+ */
73
+ const extractPaymentDetails = (tx, receipt, currentBlockNumber) => {
74
+ const txRecord = tx;
75
+ const rawTimestamp = txRecord["blockTimestamp"];
76
+ const timestamp = typeof rawTimestamp === "bigint" ? Number(rawTimestamp) : 0;
77
+ return R.always({
78
+ txHash: tx.hash,
79
+ from: tx.from,
80
+ to: tx.to ?? "0x",
81
+ amount: tx.value,
82
+ timestamp,
83
+ blockNumber: receipt.blockNumber,
84
+ confirmations: Number(currentBlockNumber - receipt.blockNumber),
85
+ })();
86
+ };
87
+ export { createTransactionWatcher, isValidPayment, extractPaymentDetails, };
88
+ //# sourceMappingURL=transaction-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-watcher.js","sourceRoot":"","sources":["../src/transaction-watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for x402 transaction watcher.
3
+ *
4
+ * Test files are exempt from FP rules.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=transaction-watcher.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-watcher.test.d.ts","sourceRoot":"","sources":["../src/transaction-watcher.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Tests for x402 transaction watcher.
3
+ *
4
+ * Test files are exempt from FP rules.
5
+ */
6
+ import { describe, it, expect, vi } from "vitest";
7
+ import { createTransactionWatcher, isValidPayment, extractPaymentDetails, } from "./transaction-watcher.js";
8
+ const mockConfig = {
9
+ payToAddress: "0x2222222222222222222222222222222222222222",
10
+ network: "eip155:84532",
11
+ price: "$0.001",
12
+ ethereumRpcUrl: "https://sepolia.base.org",
13
+ chainId: 84532,
14
+ lemmaApiBase: "https://workers.lemma.workers.dev",
15
+ circuitId: "x402-payment-v1",
16
+ minAmount: 1000n,
17
+ requiredConfirmations: 6,
18
+ maxProofAge: 3600,
19
+ ipfsGateway: "https://ipfs.io/ipfs/",
20
+ };
21
+ const mockTx = {
22
+ hash: "0xabc123",
23
+ from: "0x1111111111111111111111111111111111111111",
24
+ to: "0x2222222222222222222222222222222222222222",
25
+ value: 2000n,
26
+ blockNumber: 1000n,
27
+ blockTimestamp: 1712000000n,
28
+ gasUsed: 21000n,
29
+ effectiveGasPrice: 1000000000n,
30
+ };
31
+ const mockReceipt = {
32
+ status: "success",
33
+ blockNumber: 1000n,
34
+ confirmations: 6,
35
+ gasUsed: 21000n,
36
+ effectiveGasPrice: 1000000000n,
37
+ };
38
+ describe("Transaction Watcher", () => {
39
+ it("should create a watcher", () => {
40
+ const watcher = createTransactionWatcher(mockConfig, {});
41
+ expect(watcher).toBeDefined();
42
+ expect(typeof watcher.start).toBe("function");
43
+ expect(typeof watcher.stop).toBe("function");
44
+ expect(typeof watcher.onPaymentDetected).toBe("function");
45
+ expect(typeof watcher.getState).toBe("function");
46
+ });
47
+ it("should register payment detected callbacks", async () => {
48
+ const watcher = createTransactionWatcher(mockConfig, {});
49
+ const callback = vi.fn();
50
+ // Callbacks return Promises
51
+ const promise = watcher.onPaymentDetected(callback);
52
+ expect(promise).toBeInstanceOf(Promise);
53
+ await promise;
54
+ });
55
+ it("should return watcher state", () => {
56
+ const watcher = createTransactionWatcher(mockConfig, {});
57
+ const state = watcher.getState();
58
+ expect(state.isRunning).toBe(false);
59
+ expect(Array.isArray(state.detectedPayments)).toBe(true);
60
+ });
61
+ });
62
+ describe("isValidPayment", () => {
63
+ it("should validate a correct payment", () => {
64
+ const currentBlockNumber = 1010n; // Sufficient confirmations (10 confirmations)
65
+ const result = isValidPayment(mockTx, mockReceipt, mockConfig, currentBlockNumber);
66
+ expect(result).toBe(true);
67
+ });
68
+ it("should reject payment to wrong recipient", () => {
69
+ const badTx = { ...mockTx, to: "0x3333333333333333333333333333333333333333" };
70
+ const currentBlockNumber = 1010n;
71
+ const result = isValidPayment(badTx, mockReceipt, mockConfig, currentBlockNumber);
72
+ expect(result).toBe(false);
73
+ });
74
+ it("should reject payment below minimum amount", () => {
75
+ const lowTx = { ...mockTx, value: 500n };
76
+ const currentBlockNumber = 1010n;
77
+ const result = isValidPayment(lowTx, mockReceipt, mockConfig, currentBlockNumber);
78
+ expect(result).toBe(false);
79
+ });
80
+ it("should reject failed transaction", () => {
81
+ const failedReceipt = { ...mockReceipt, status: "reverted" };
82
+ const currentBlockNumber = 1010n;
83
+ const result = isValidPayment(mockTx, failedReceipt, mockConfig, currentBlockNumber);
84
+ expect(result).toBe(false);
85
+ });
86
+ it("should reject payment with insufficient confirmations", () => {
87
+ const currentBlockNumber = 1002n; // Only 2 confirmations (1002 - 1000 = 2)
88
+ const result = isValidPayment(mockTx, mockReceipt, mockConfig, currentBlockNumber);
89
+ expect(result).toBe(false);
90
+ });
91
+ });
92
+ describe("extractPaymentDetails", () => {
93
+ it("should extract payment details from transaction and receipt", () => {
94
+ const currentBlockNumber = 1010n;
95
+ const details = extractPaymentDetails(mockTx, mockReceipt, currentBlockNumber);
96
+ expect(details.txHash).toBe("0xabc123");
97
+ expect(details.from).toBe("0x1111111111111111111111111111111111111111");
98
+ expect(details.to).toBe("0x2222222222222222222222222222222222222222");
99
+ expect(details.amount).toBe(2000n);
100
+ expect(details.timestamp).toBe(1712000000); // Retrieved from blockTimestamp
101
+ expect(details.blockNumber).toBe(1000n);
102
+ expect(details.confirmations).toBe(10);
103
+ });
104
+ it("should handle missing blockTimestamp", () => {
105
+ const txNoTimestamp = { ...mockTx, blockTimestamp: undefined };
106
+ const currentBlockNumber = 1010n;
107
+ const details = extractPaymentDetails(txNoTimestamp, mockReceipt, currentBlockNumber);
108
+ expect(details.timestamp).toBe(0);
109
+ });
110
+ });
111
+ //# sourceMappingURL=transaction-watcher.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-watcher.test.js","sourceRoot":"","sources":["../src/transaction-watcher.test.ts"],"names":[],"mappings":"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"}