@lemmaoracle/x402 0.1.1 → 0.1.3

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 (146) hide show
  1. package/dist/advanced/index.d.ts +14 -0
  2. package/dist/advanced/index.d.ts.map +1 -0
  3. package/dist/advanced/index.js +14 -0
  4. package/dist/advanced/index.js.map +1 -0
  5. package/dist/index.d.ts +25 -42
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +25 -77
  8. package/dist/index.js.map +1 -1
  9. package/dist/lemma-config.d.ts +41 -0
  10. package/dist/lemma-config.d.ts.map +1 -0
  11. package/dist/lemma-config.js +12 -0
  12. package/dist/lemma-config.js.map +1 -0
  13. package/dist/lemma-discovery.d.ts +37 -0
  14. package/dist/lemma-discovery.d.ts.map +1 -0
  15. package/dist/lemma-discovery.js +104 -0
  16. package/dist/lemma-discovery.js.map +1 -0
  17. package/dist/lemma-server.d.ts +30 -0
  18. package/dist/lemma-server.d.ts.map +1 -0
  19. package/dist/lemma-server.js +169 -0
  20. package/dist/lemma-server.js.map +1 -0
  21. package/dist/lemma-submission.d.ts +44 -0
  22. package/dist/lemma-submission.d.ts.map +1 -0
  23. package/dist/lemma-submission.js +81 -0
  24. package/dist/lemma-submission.js.map +1 -0
  25. package/package.json +14 -14
  26. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-1775996174982.json +0 -34
  27. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-1775996423983.json +0 -51
  28. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-1775996907850.json +0 -51
  29. package/broadcast/DeployPaymentVerifier.s.sol/10143/run-latest.json +0 -51
  30. package/cache/DeployPaymentVerifier.s.sol/10143/run-1775996174982.json +0 -7
  31. package/cache/DeployPaymentVerifier.s.sol/10143/run-1775996423983.json +0 -7
  32. package/cache/DeployPaymentVerifier.s.sol/10143/run-1775996907850.json +0 -7
  33. package/cache/DeployPaymentVerifier.s.sol/10143/run-latest.json +0 -7
  34. package/cache/solidity-files-cache.json +0 -1
  35. package/circuits/README.md +0 -78
  36. package/circuits/payment-comprehensive.test.mjs +0 -272
  37. package/circuits/payment.circom +0 -89
  38. package/circuits/payment.test.mjs +0 -173
  39. package/dist/proof-generator.d.ts +0 -26
  40. package/dist/proof-generator.d.ts.map +0 -1
  41. package/dist/proof-generator.js +0 -154
  42. package/dist/proof-generator.js.map +0 -1
  43. package/dist/proof-generator.test.d.ts +0 -7
  44. package/dist/proof-generator.test.d.ts.map +0 -1
  45. package/dist/proof-generator.test.js +0 -121
  46. package/dist/proof-generator.test.js.map +0 -1
  47. package/dist/transaction-watcher.d.ts +0 -42
  48. package/dist/transaction-watcher.d.ts.map +0 -1
  49. package/dist/transaction-watcher.js +0 -88
  50. package/dist/transaction-watcher.js.map +0 -1
  51. package/dist/transaction-watcher.test.d.ts +0 -7
  52. package/dist/transaction-watcher.test.d.ts.map +0 -1
  53. package/dist/transaction-watcher.test.js +0 -111
  54. package/dist/transaction-watcher.test.js.map +0 -1
  55. package/dist/types.d.ts +0 -76
  56. package/dist/types.d.ts.map +0 -1
  57. package/dist/types.js +0 -2
  58. package/dist/types.js.map +0 -1
  59. package/foundry.lock +0 -11
  60. package/foundry.toml +0 -16
  61. package/lib/forge-std/.gitattributes +0 -1
  62. package/lib/forge-std/.github/CODEOWNERS +0 -1
  63. package/lib/forge-std/.github/dependabot.yml +0 -6
  64. package/lib/forge-std/.github/workflows/ci.yml +0 -161
  65. package/lib/forge-std/.github/workflows/sync.yml +0 -36
  66. package/lib/forge-std/CONTRIBUTING.md +0 -193
  67. package/lib/forge-std/LICENSE-APACHE +0 -203
  68. package/lib/forge-std/LICENSE-MIT +0 -25
  69. package/lib/forge-std/README.md +0 -314
  70. package/lib/forge-std/RELEASE_CHECKLIST.md +0 -12
  71. package/lib/forge-std/foundry.toml +0 -18
  72. package/lib/forge-std/package.json +0 -16
  73. package/lib/forge-std/scripts/vm.py +0 -636
  74. package/lib/forge-std/src/Base.sol +0 -48
  75. package/lib/forge-std/src/Config.sol +0 -60
  76. package/lib/forge-std/src/LibVariable.sol +0 -477
  77. package/lib/forge-std/src/Script.sol +0 -28
  78. package/lib/forge-std/src/StdAssertions.sol +0 -1300
  79. package/lib/forge-std/src/StdChains.sol +0 -303
  80. package/lib/forge-std/src/StdCheats.sol +0 -825
  81. package/lib/forge-std/src/StdConfig.sol +0 -632
  82. package/lib/forge-std/src/StdConstants.sol +0 -30
  83. package/lib/forge-std/src/StdError.sol +0 -15
  84. package/lib/forge-std/src/StdInvariant.sol +0 -161
  85. package/lib/forge-std/src/StdJson.sol +0 -275
  86. package/lib/forge-std/src/StdMath.sol +0 -47
  87. package/lib/forge-std/src/StdStorage.sol +0 -476
  88. package/lib/forge-std/src/StdStyle.sol +0 -333
  89. package/lib/forge-std/src/StdToml.sol +0 -275
  90. package/lib/forge-std/src/StdUtils.sol +0 -200
  91. package/lib/forge-std/src/Test.sol +0 -32
  92. package/lib/forge-std/src/Vm.sol +0 -2533
  93. package/lib/forge-std/src/console.sol +0 -1551
  94. package/lib/forge-std/src/console2.sol +0 -4
  95. package/lib/forge-std/src/interfaces/IERC1155.sol +0 -105
  96. package/lib/forge-std/src/interfaces/IERC165.sol +0 -12
  97. package/lib/forge-std/src/interfaces/IERC20.sol +0 -43
  98. package/lib/forge-std/src/interfaces/IERC4626.sol +0 -190
  99. package/lib/forge-std/src/interfaces/IERC6909.sol +0 -72
  100. package/lib/forge-std/src/interfaces/IERC721.sol +0 -164
  101. package/lib/forge-std/src/interfaces/IERC7540.sol +0 -145
  102. package/lib/forge-std/src/interfaces/IERC7575.sol +0 -241
  103. package/lib/forge-std/src/interfaces/IMulticall3.sol +0 -68
  104. package/lib/forge-std/src/safeconsole.sol +0 -13248
  105. package/lib/forge-std/test/CommonBase.t.sol +0 -44
  106. package/lib/forge-std/test/Config.t.sol +0 -381
  107. package/lib/forge-std/test/LibVariable.t.sol +0 -452
  108. package/lib/forge-std/test/StdAssertions.t.sol +0 -141
  109. package/lib/forge-std/test/StdChains.t.sol +0 -227
  110. package/lib/forge-std/test/StdCheats.t.sol +0 -638
  111. package/lib/forge-std/test/StdConstants.t.sol +0 -38
  112. package/lib/forge-std/test/StdError.t.sol +0 -119
  113. package/lib/forge-std/test/StdJson.t.sol +0 -49
  114. package/lib/forge-std/test/StdMath.t.sol +0 -202
  115. package/lib/forge-std/test/StdStorage.t.sol +0 -532
  116. package/lib/forge-std/test/StdStyle.t.sol +0 -110
  117. package/lib/forge-std/test/StdToml.t.sol +0 -49
  118. package/lib/forge-std/test/StdUtils.t.sol +0 -342
  119. package/lib/forge-std/test/Vm.t.sol +0 -18
  120. package/lib/forge-std/test/compilation/CompilationScript.sol +0 -8
  121. package/lib/forge-std/test/compilation/CompilationScriptBase.sol +0 -8
  122. package/lib/forge-std/test/compilation/CompilationTest.sol +0 -8
  123. package/lib/forge-std/test/compilation/CompilationTestBase.sol +0 -8
  124. package/lib/forge-std/test/fixtures/broadcast.log.json +0 -187
  125. package/lib/forge-std/test/fixtures/config.toml +0 -81
  126. package/lib/forge-std/test/fixtures/test.json +0 -8
  127. package/lib/forge-std/test/fixtures/test.toml +0 -6
  128. package/package.json.backup +0 -55
  129. package/scripts/DeployPaymentVerifier.s.sol +0 -18
  130. package/scripts/build.sh +0 -61
  131. package/scripts/deploy.sh +0 -65
  132. package/scripts/fix-verifier.mjs +0 -64
  133. package/scripts/register-circuit.ts +0 -213
  134. package/scripts/test-with-circuit.mjs +0 -88
  135. package/src/index.ts +0 -115
  136. package/src/proof-generator.test.ts +0 -139
  137. package/src/proof-generator.ts +0 -220
  138. package/src/transaction-watcher.test.ts +0 -153
  139. package/src/transaction-watcher.ts +0 -154
  140. package/src/types.ts +0 -110
  141. package/tsconfig.json +0 -14
  142. package/tsconfig.tsbuildinfo +0 -1
  143. package/vitest.config.ts +0 -18
  144. package/workers/x402-facilitator/src/index.ts +0 -582
  145. package/workers/x402-facilitator/src/x402-env.d.ts +0 -25
  146. package/workers/x402-facilitator/wrangler.toml +0 -19
package/src/index.ts DELETED
@@ -1,115 +0,0 @@
1
- import { create, type LemmaClient } from "@lemmaoracle/sdk";
2
- import * as R from "ramda";
3
- import type { Config, Disclosure, Proof, Transaction, ProofResult } from "./types.js";
4
- import { createProofGenerator } from "./proof-generator.js";
5
-
6
- /**
7
- * Create a Lemma API client from config.
8
- */
9
- const createLemmaClient = (config: Config): LemmaClient =>
10
- create({
11
- apiBase: config.lemmaApiBase,
12
- apiKey: config.lemmaApiKey,
13
- });
14
-
15
- /**
16
- * Build a disclosure object from a proof.
17
- */
18
- const disclosure = (proof: Proof): Disclosure =>
19
- ({
20
- condition: { circuitId: proof.circuitId },
21
- proof: proof.proof,
22
- inputs: proof.inputs,
23
- });
24
-
25
- /**
26
- * Build disclosure with empty proof for initial query (will be filled by facilitator).
27
- */
28
- const emptyDisclosure = (circuitId: string): Disclosure =>
29
- ({
30
- condition: { circuitId },
31
- proof: "",
32
- inputs: [],
33
- });
34
-
35
- /**
36
- * Create a configured facilitator client with proof generation capabilities.
37
- *
38
- * Usage:
39
- * const facilitator = facilitator(config);
40
- *
41
- * // Generate disclosure with payment proof
42
- * const disclosure = await facilitator.generateDisclosure(txHash);
43
- *
44
- * // Query Lemma API
45
- * const results = await lemmaApi.query({ disclosure });
46
- */
47
- const facilitator = (config: Config) => {
48
- const lemmaClient = createLemmaClient(config);
49
- const proofGenerator = createProofGenerator(config, lemmaClient);
50
-
51
- return {
52
- /**
53
- * Generate a disclosure with payment proof for a transaction.
54
- */
55
- generateDisclosure: async (txHash: `0x${string}`): Promise<Disclosure> => {
56
- const { proof } = await proofGenerator.generateProof(txHash);
57
-
58
- return disclosure(proof);
59
- },
60
-
61
- /**
62
- * Get an empty disclosure template with condition for the configured circuit.
63
- */
64
- getEmptyDisclosure: (_?: undefined): Disclosure =>
65
- emptyDisclosure(config.circuitId),
66
-
67
- /**
68
- * Get the configuration.
69
- */
70
- getConfig: (_?: undefined): Config => config,
71
-
72
- /**
73
- * Get the Lemma client.
74
- */
75
- getLemmaClient: (_?: undefined): LemmaClient => lemmaClient,
76
- };
77
- };
78
-
79
- /**
80
- * Default x402 facilitator configuration for Base Sepolia.
81
- */
82
- const defaultConfig = (overrides: Partial<Config> = {}): Config =>
83
- R.mergeRight(
84
- {
85
- payToAddress: "0x" as `0x${string}`,
86
- network: "eip155:84532",
87
- price: "$0.001",
88
- ethereumRpcUrl: "https://sepolia.base.org",
89
- chainId: 84532,
90
- lemmaApiBase: "https://workers.lemma.workers.dev",
91
- circuitId: "x402-payment-v1",
92
- minAmount: 1000n, // $0.001 USDC in smallest units (6 decimals)
93
- requiredConfirmations: 6,
94
- maxProofAge: 3600, // 1 hour
95
- ipfsGateway: "https://ipfs.io/ipfs/",
96
- },
97
- overrides,
98
- );
99
-
100
- export {
101
- facilitator,
102
- createProofGenerator,
103
- disclosure,
104
- emptyDisclosure,
105
- defaultConfig,
106
- // createLemmaClient is not exported
107
- };
108
-
109
- export type {
110
- Config,
111
- Disclosure,
112
- Proof,
113
- Transaction,
114
- ProofResult,
115
- };
@@ -1,139 +0,0 @@
1
- /**
2
- * Tests for x402 payment proof generator.
3
- *
4
- * Test files are exempt from FP rules.
5
- */
6
-
7
- import { describe, it, expect, vi, beforeEach } from "vitest";
8
- import { createProofGenerator } from "./proof-generator.js";
9
- import type { Config } from "./types.js";
10
-
11
- // Mock viem
12
- vi.mock("viem", async () => {
13
- const actual = await vi.importActual("viem");
14
- return {
15
- ...actual,
16
- createPublicClient: vi.fn(() => ({
17
- getTransaction: vi.fn().mockResolvedValue({
18
- hash: "0xabc123",
19
- from: "0xsender",
20
- to: "0x2222222222222222222222222222222222222222",
21
- value: 1000n,
22
- }),
23
- getTransactionReceipt: vi.fn().mockResolvedValue({
24
- status: "success",
25
- blockNumber: 1000n,
26
- gasUsed: 21000n,
27
- effectiveGasPrice: 1000000000n,
28
- confirmations: 6,
29
- }),
30
- getBlock: vi.fn().mockResolvedValue({
31
- number: 1006n,
32
- timestamp: 1712000000n,
33
- }),
34
- })),
35
- };
36
- });
37
-
38
- // Mock Lemma SDK
39
- vi.mock("@lemmaoracle/sdk", async () => {
40
- const actual = await vi.importActual("@lemmaoracle/sdk");
41
- return {
42
- ...actual,
43
- prover: {
44
- prove: vi.fn().mockResolvedValue({
45
- proof: "mock-proof-base64",
46
- publicInputs: ["input1", "input2"],
47
- }),
48
- },
49
- createClient: vi.fn().mockReturnValue({
50
- apiBase: "https://workers.lemma.workers.dev",
51
- }),
52
- };
53
- });
54
-
55
- const mockConfig: Config = {
56
- payToAddress: "0x2222222222222222222222222222222222222222" as `0x${string}`,
57
- network: "eip155:84532",
58
- price: "$0.001",
59
- ethereumRpcUrl: "https://sepolia.base.org",
60
- chainId: 84532,
61
- lemmaApiBase: "https://workers.lemma.workers.dev",
62
- circuitId: "x402-payment-v1",
63
- minAmount: 1000n,
64
- requiredConfirmations: 6,
65
- maxProofAge: 3600,
66
- ipfsGateway: "https://ipfs.io/ipfs/",
67
- };
68
-
69
- const mockLemmaClient = {
70
- apiBase: "https://workers.lemma.workers.dev",
71
- };
72
-
73
- describe("X402 Proof Generator", () => {
74
- beforeEach(() => {
75
- vi.clearAllMocks();
76
- });
77
-
78
- it("should create a proof generator", () => {
79
- const generator = createProofGenerator(mockConfig, mockLemmaClient as any);
80
-
81
- expect(generator).toBeDefined();
82
- expect(typeof generator.generateProof).toBe("function");
83
- expect(typeof generator.toFieldElements).toBe("function");
84
- });
85
-
86
- it("should convert payment details to field elements", async () => {
87
- const generator = createProofGenerator(mockConfig, mockLemmaClient as any);
88
-
89
- const mockPayment = {
90
- txHash: "0xabc123" as `0x${string}`,
91
- from: "0x1111111111111111111111111111111111111111" as `0x${string}`,
92
- to: "0x2222222222222222222222222222222222222222" as `0x${string}`,
93
- amount: 1000n,
94
- timestamp: 1712000000,
95
- blockNumber: 1000n,
96
- confirmations: 6,
97
- };
98
-
99
- const result = await generator.toFieldElements(mockPayment, mockConfig);
100
-
101
- expect(result).toBeDefined();
102
- expect(result.witness).toBeDefined();
103
- expect(result.publicInputs).toBeDefined();
104
- expect(result.witness.amount).toBeDefined();
105
- expect(result.witness.minAmount).toBeDefined();
106
- });
107
-
108
- it("should handle empty txHash gracefully", async () => {
109
- const generator = createProofGenerator(mockConfig, mockLemmaClient as any);
110
-
111
- expect(generator.generateProof).toBeDefined();
112
- });
113
- });
114
-
115
- describe("Field Element Conversion", () => {
116
- it("should convert addresses to field elements", async () => {
117
- const generator = createProofGenerator(mockConfig, mockLemmaClient as any);
118
-
119
- const mockPayment = {
120
- txHash: "0xabc123" as `0x${string}`,
121
- from: "0x1111111111111111111111111111111111111111" as `0x${string}`,
122
- to: "0x2222222222222222222222222222222222222222" as `0x${string}`,
123
- amount: 1000n,
124
- timestamp: 1712000000,
125
- blockNumber: 1000n,
126
- confirmations: 6,
127
- };
128
-
129
- const { witness } = await generator.toFieldElements(mockPayment, mockConfig);
130
-
131
- // Verify field elements are present and not null
132
- expect(witness.txHashPacked_0).toBeDefined();
133
- expect(witness.txHashPacked_1).toBeDefined();
134
- expect(witness.recipientLow).toBeDefined();
135
- expect(witness.amount).toBeDefined();
136
- expect(witness.timestamp).toBeDefined();
137
- expect(witness.minAmount).toBeDefined();
138
- });
139
- });
@@ -1,220 +0,0 @@
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
-
9
- import { createPublicClient, http, type PublicClient } from "viem";
10
- import { prover, type LemmaClient } from "@lemmaoracle/sdk";
11
- import * as R from "ramda";
12
- import type {
13
- ProofResult,
14
- Config,
15
- Transaction,
16
- Proof,
17
- } from "./types.js";
18
-
19
- // ---------------------------------------------------------------------------
20
- // Constants
21
- // ---------------------------------------------------------------------------
22
-
23
- /** Default IPFS gateway if not specified in config */
24
- const _DEFAULT_IPFS_GATEWAY = "https://ipfs.io/ipfs/";
25
-
26
- /** Poseidon hash function for field element hashing */
27
- const toFieldElement = (value: string): string =>
28
- BigInt(value) < 0n
29
- ? String(BigInt(value) % 21888242871839275222246405745257275088548364400416034343698204186575808495617n)
30
- : value;
31
-
32
- // ---------------------------------------------------------------------------
33
- // Proof Generator Class
34
- // ---------------------------------------------------------------------------
35
-
36
- /**
37
- * Generates x402 payment proofs using Lemma's prover infrastructure.
38
- *
39
- * Usage:
40
- * const generator = new X402ProofGenerator(config, lemmaClient);
41
- * const result = await generator.generateProof(txHash);
42
- */
43
- const createProofGenerator = (
44
- config: Config,
45
- lemmaClient: LemmaClient,
46
- ): Readonly<{
47
- generateProof: (txHash: `0x${string}`) => Promise<ProofResult>;
48
- toFieldElements: (
49
- payment: Transaction,
50
- config: Config,
51
- ) => Readonly<{ witness: Record<string, string>; publicInputs: string[] }>;
52
- }> => {
53
- /** Create public client for transaction inspection */
54
- const publicClient: PublicClient = createPublicClient({
55
- transport: http(config.ethereumRpcUrl),
56
- });
57
-
58
- return {
59
- /**
60
- * Generate a payment proof for a given transaction hash.
61
- * This fetches the transaction details, computes the witness,
62
- * and generates the ZK proof.
63
- */
64
- generateProof: async (txHash: `0x${string}`): Promise<ProofResult> => {
65
- // Step 1: Fetch transaction details from blockchain
66
- const payment = await fetchPaymentTransaction(txHash, publicClient);
67
-
68
- // Step 2: Generate proof
69
- const proofResult = await generateZKProof(
70
- lemmaClient,
71
- payment,
72
- config,
73
- );
74
-
75
- return R.always({
76
- payment,
77
- proof: proofResult,
78
- })();
79
- },
80
-
81
- /**
82
- * Convert payment transaction details to circuit field elements.
83
- */
84
- toFieldElements: (
85
- payment: Transaction,
86
- cfg: Config,
87
- ) => {
88
- // Split 256-bit txHash into two 128-bit elements
89
- const txHashBigInt = BigInt(payment.txHash);
90
- const upper128 = toFieldElement(String(txHashBigInt >> 128n));
91
- const lower128 = toFieldElement(String(txHashBigInt & ((1n << 128n) - 1n)));
92
-
93
- // Split 160-bit recipient address
94
- const recipientBigInt = BigInt(payment.to);
95
- const recipientLow = toFieldElement(String(recipientBigInt & ((1n << 128n) - 1n)));
96
- const recipientHigh = toFieldElement(String(recipientBigInt >> 128n));
97
-
98
- // Amount and timestamp
99
- const amount = toFieldElement(String(payment.amount));
100
- const timestamp = toFieldElement(String(payment.timestamp));
101
- const minAmount = toFieldElement(String(cfg.minAmount));
102
-
103
- return R.always({
104
- witness: {
105
- txHashPacked_0: lower128,
106
- txHashPacked_1: upper128,
107
- recipientLow,
108
- recipientHigh,
109
- amount,
110
- timestamp,
111
- minAmount,
112
- },
113
- publicInputs: [
114
- // commitment will be computed during proof generation
115
- toFieldElement(String(cfg.minAmount)), // minAmountPublic
116
- toFieldElement(String(cfg.maxProofAge)), // timestampMax
117
- ],
118
- })();
119
- },
120
- };
121
- };
122
-
123
- // ---------------------------------------------------------------------------
124
- // Private Helpers
125
- // ---------------------------------------------------------------------------
126
-
127
- /**
128
- * Fetch payment transaction details from the blockchain.
129
- */
130
- const fetchPaymentTransaction = async (
131
- txHash: `0x${string}`,
132
- client: PublicClient,
133
- ): Promise<Transaction> => {
134
- const txPromise = client.getTransaction({ hash: txHash });
135
- const receiptPromise = client.getTransactionReceipt({ hash: txHash });
136
- const blockPromise = client.getBlock({ blockTag: "latest" });
137
-
138
- const [tx, receipt, block] = await Promise.all([
139
- txPromise,
140
- receiptPromise,
141
- blockPromise,
142
- ]);
143
-
144
- return receipt.status !== "success"
145
- ? Promise.reject(new Error(`Transaction ${txHash} failed`))
146
- : client.getBlock({ blockNumber: receipt.blockNumber }).then(
147
- (blockData) =>
148
- R.always({
149
- txHash,
150
- from: tx.from,
151
- to: tx.to ?? ("0x" as `0x${string}`),
152
- amount: tx.value + receipt.effectiveGasPrice * receipt.gasUsed,
153
- timestamp: Number(blockData.timestamp),
154
- blockNumber: receipt.blockNumber,
155
- confirmations: Number(block.number - receipt.blockNumber),
156
- })(),
157
- );
158
- };
159
-
160
- /**
161
- * Generate ZK proof for the payment transaction.
162
- */
163
- const generateZKProof = async (
164
- lemmaClient: LemmaClient,
165
- payment: Transaction,
166
- config: Config,
167
- ): Promise<Proof> => {
168
- // Build witness from payment transaction
169
- const builder = createProofGenerator(config, lemmaClient);
170
- const { witness, publicInputs } = builder.toFieldElements(payment, config);
171
-
172
- // Generate proof using Lemma SDK
173
- const proofResult = await prover.prove(lemmaClient, {
174
- circuitId: config.circuitId,
175
- witness,
176
- });
177
-
178
- // Compute the commitment for public inputs
179
- const commitment = computeCommitment(witness, publicInputs);
180
-
181
- return R.always({
182
- proof: proofResult.proof,
183
- inputs: [commitment, ...publicInputs],
184
- circuitId: config.circuitId,
185
- generatedAt: Date.now(),
186
- })();
187
- };
188
-
189
- /**
190
- * Compute the commitment hash for the circuit public inputs.
191
- */
192
- const computeCommitment = (
193
- witness: Record<string, string>,
194
- _publicInputs: string[],
195
- ): string => {
196
- // The commitment is computed from:
197
- // poseidon(txHashPacked[0], txHashPacked[1], recipientLow, amount, timestamp, minAmount)
198
- // This should match the public commitment used in the circuit
199
- const values = [
200
- witness.txHashPacked_0,
201
- witness.txHashPacked_1,
202
- witness.recipientLow,
203
- witness.amount,
204
- witness.timestamp,
205
- witness.minAmount,
206
- ];
207
-
208
- // In a real implementation, use poseidon from circomlib
209
- // For now, we use a simple hash placeholder
210
- return values.join(",");
211
- };
212
-
213
- export type {
214
- ProofResult,
215
- Config,
216
- Proof,
217
- Transaction,
218
- };
219
-
220
- export { createProofGenerator };
@@ -1,153 +0,0 @@
1
- /**
2
- * Tests for x402 transaction watcher.
3
- *
4
- * Test files are exempt from FP rules.
5
- */
6
-
7
- import { describe, it, expect, vi } from "vitest";
8
- import {
9
- createTransactionWatcher,
10
- isValidPayment,
11
- extractPaymentDetails,
12
- } from "./transaction-watcher.js";
13
- import type { Config } from "./types.js";
14
-
15
- const mockConfig: Config = {
16
- payToAddress: "0x2222222222222222222222222222222222222222" as `0x${string}`,
17
- network: "eip155:84532",
18
- price: "$0.001",
19
- ethereumRpcUrl: "https://sepolia.base.org",
20
- chainId: 84532,
21
- lemmaApiBase: "https://workers.lemma.workers.dev",
22
- circuitId: "x402-payment-v1",
23
- minAmount: 1000n,
24
- requiredConfirmations: 6,
25
- maxProofAge: 3600,
26
- ipfsGateway: "https://ipfs.io/ipfs/",
27
- };
28
-
29
- const mockTx = {
30
- hash: "0xabc123",
31
- from: "0x1111111111111111111111111111111111111111",
32
- to: "0x2222222222222222222222222222222222222222",
33
- value: 2000n,
34
- blockNumber: 1000n,
35
- blockTimestamp: 1712000000n,
36
- gasUsed: 21000n,
37
- effectiveGasPrice: 1000000000n,
38
- };
39
-
40
- const mockReceipt = {
41
- status: "success" as const,
42
- blockNumber: 1000n,
43
- confirmations: 6,
44
- gasUsed: 21000n,
45
- effectiveGasPrice: 1000000000n,
46
- };
47
-
48
- describe("Transaction Watcher", () => {
49
- it("should create a watcher", () => {
50
- const watcher = createTransactionWatcher(mockConfig, {});
51
-
52
- expect(watcher).toBeDefined();
53
- expect(typeof watcher.start).toBe("function");
54
- expect(typeof watcher.stop).toBe("function");
55
- expect(typeof watcher.onPaymentDetected).toBe("function");
56
- expect(typeof watcher.getState).toBe("function");
57
- });
58
-
59
- it("should register payment detected callbacks", async () => {
60
- const watcher = createTransactionWatcher(mockConfig, {});
61
- const callback = vi.fn();
62
-
63
- // Callbacks return Promises
64
- const promise = watcher.onPaymentDetected(callback);
65
-
66
- expect(promise).toBeInstanceOf(Promise);
67
- await promise;
68
- });
69
-
70
- it("should return watcher state", () => {
71
- const watcher = createTransactionWatcher(mockConfig, {});
72
- const state = watcher.getState();
73
-
74
- expect(state.isRunning).toBe(false);
75
- expect(Array.isArray(state.detectedPayments)).toBe(true);
76
- });
77
- });
78
-
79
- describe("isValidPayment", () => {
80
- it("should validate a correct payment", () => {
81
- const currentBlockNumber = 1010n; // Sufficient confirmations (10 confirmations)
82
- const result = isValidPayment(mockTx as any, mockReceipt as any, mockConfig, currentBlockNumber);
83
-
84
- expect(result).toBe(true);
85
- });
86
-
87
- it("should reject payment to wrong recipient", () => {
88
- const badTx = { ...mockTx, to: "0x3333333333333333333333333333333333333333" };
89
- const currentBlockNumber = 1010n;
90
-
91
- const result = isValidPayment(badTx as any, mockReceipt as any, mockConfig, currentBlockNumber);
92
-
93
- expect(result).toBe(false);
94
- });
95
-
96
- it("should reject payment below minimum amount", () => {
97
- const lowTx = { ...mockTx, value: 500n };
98
- const currentBlockNumber = 1010n;
99
-
100
- const result = isValidPayment(lowTx as any, mockReceipt as any, mockConfig, currentBlockNumber);
101
-
102
- expect(result).toBe(false);
103
- });
104
-
105
- it("should reject failed transaction", () => {
106
- const failedReceipt = { ...mockReceipt, status: "reverted" as const };
107
- const currentBlockNumber = 1010n;
108
-
109
- const result = isValidPayment(mockTx as any, failedReceipt as any, mockConfig, currentBlockNumber);
110
-
111
- expect(result).toBe(false);
112
- });
113
-
114
- it("should reject payment with insufficient confirmations", () => {
115
- const currentBlockNumber = 1002n; // Only 2 confirmations (1002 - 1000 = 2)
116
- const result = isValidPayment(mockTx as any, mockReceipt as any, mockConfig, currentBlockNumber);
117
-
118
- expect(result).toBe(false);
119
- });
120
- });
121
-
122
- describe("extractPaymentDetails", () => {
123
- it("should extract payment details from transaction and receipt", () => {
124
- const currentBlockNumber = 1010n;
125
-
126
- const details = extractPaymentDetails(
127
- mockTx as any,
128
- mockReceipt as any,
129
- currentBlockNumber,
130
- );
131
-
132
- expect(details.txHash).toBe("0xabc123");
133
- expect(details.from).toBe("0x1111111111111111111111111111111111111111");
134
- expect(details.to).toBe("0x2222222222222222222222222222222222222222");
135
- expect(details.amount).toBe(2000n);
136
- expect(details.timestamp).toBe(1712000000); // Retrieved from blockTimestamp
137
- expect(details.blockNumber).toBe(1000n);
138
- expect(details.confirmations).toBe(10);
139
- });
140
-
141
- it("should handle missing blockTimestamp", () => {
142
- const txNoTimestamp = { ...mockTx, blockTimestamp: undefined };
143
- const currentBlockNumber = 1010n;
144
-
145
- const details = extractPaymentDetails(
146
- txNoTimestamp as any,
147
- mockReceipt as any,
148
- currentBlockNumber,
149
- );
150
-
151
- expect(details.timestamp).toBe(0);
152
- });
153
- });