@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,81 @@
1
+ # ------------------------------------------------
2
+ # EXAMPLE DEPLOYMENT CONFIG
3
+ # ------------------------------------------------
4
+
5
+ # -- MAINNET -------------------------------------
6
+
7
+ [mainnet]
8
+ endpoint_url = "${MAINNET_RPC}"
9
+
10
+ [mainnet.bool]
11
+ is_live = true
12
+ bool_array = [true, false]
13
+
14
+ [mainnet.address]
15
+ weth = "${WETH_MAINNET}"
16
+ deps = [
17
+ "0x0000000000000000000000000000000000000000",
18
+ "0x1111111111111111111111111111111111111111",
19
+ ]
20
+
21
+ [mainnet.uint]
22
+ number = 1234
23
+ number_array = [5678, 9999]
24
+
25
+ [mainnet.int]
26
+ signed_number = -1234
27
+ signed_number_array = [-5678, 9999]
28
+
29
+ [mainnet.bytes32]
30
+ word = "0x00000000000000000000000000000000000000000000000000000000000004d2" # 1234
31
+ word_array = [
32
+ "0x000000000000000000000000000000000000000000000000000000000000162e", # 5678
33
+ "0x000000000000000000000000000000000000000000000000000000000000270f", # 9999
34
+ ]
35
+
36
+ [mainnet.bytes]
37
+ b = "0xabcd"
38
+ b_array = ["0xdead", "0xbeef"]
39
+
40
+ [mainnet.string]
41
+ str = "foo"
42
+ str_array = ["bar", "baz"]
43
+
44
+ # -- OPTIMISM ------------------------------------
45
+
46
+ [optimism]
47
+ endpoint_url = "${OPTIMISM_RPC}"
48
+
49
+ [optimism.bool]
50
+ is_live = false
51
+ bool_array = [false, true]
52
+
53
+ [optimism.address]
54
+ weth = "${WETH_OPTIMISM}"
55
+ deps = [
56
+ "0x2222222222222222222222222222222222222222",
57
+ "0x3333333333333333333333333333333333333333",
58
+ ]
59
+
60
+ [optimism.uint]
61
+ number = 9999
62
+ number_array = [1234, 5678]
63
+
64
+ [optimism.int]
65
+ signed_number = 9999
66
+ signed_number_array = [-1234, -5678]
67
+
68
+ [optimism.bytes32]
69
+ word = "0x000000000000000000000000000000000000000000000000000000000000270f" # 9999
70
+ word_array = [
71
+ "0x00000000000000000000000000000000000000000000000000000000000004d2", # 1234
72
+ "0x000000000000000000000000000000000000000000000000000000000000162e", # 5678
73
+ ]
74
+
75
+ [optimism.bytes]
76
+ b = "0xdcba"
77
+ b_array = ["0xc0ffee", "0xbabe"]
78
+
79
+ [optimism.string]
80
+ str = "alice"
81
+ str_array = ["bob", "charlie"]
@@ -0,0 +1,8 @@
1
+ {
2
+ "a": 123,
3
+ "b": "test",
4
+ "c": {
5
+ "a": 123,
6
+ "b": "test"
7
+ }
8
+ }
@@ -0,0 +1,6 @@
1
+ a = 123
2
+ b = "test"
3
+
4
+ [c]
5
+ a = 123
6
+ b = "test"
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@lemmaoracle/x402",
3
+ "version": "0.1.1",
4
+ "description": "ZK-enabled x402 payment proofs for Lemma's disclosure.condition API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsc --build",
17
+ "build:circuit": "bash scripts/build.sh",
18
+ "dev": "tsc --watch",
19
+ "type-check": "tsc --noEmit",
20
+ "test": "vitest run && bash -c 'if [ ! -f \"build/payment_js/payment.wasm\" ]; then echo \"šŸ”§ Circuit not built. Building circuit first...\" && npm run build:circuit; fi && node circuits/payment.test.mjs'",
21
+ "test:vitest": "vitest run",
22
+ "test:watch": "vitest",
23
+ "test:circuit": "node circuits/payment.test.mjs",
24
+ "test:circuit:comprehensive": "node circuits/payment-comprehensive.test.mjs",
25
+ "deploy:worker": "wrangler deploy --config wrangler.toml",
26
+ "deploy": "dotenv -e ../../.env -- forge script ${SCRIPT:-scripts/DeployPaymentVerifier.s.sol} --broadcast",
27
+ "deploy:monadTestnet": "dotenv -e ../../.env -- forge script ${SCRIPT:-scripts/DeployPaymentVerifier.s.sol} --rpc-url monad_testnet --broadcast --verify",
28
+ "deploy:baseSepolia": "dotenv -e ../../.env -- forge script ${SCRIPT:-scripts/DeployPaymentVerifier.s.sol} --rpc-url base_sepolia --broadcast --verify",
29
+ "register": "tsx scripts/register-circuit.ts"
30
+ },
31
+ "dependencies": {
32
+ "@lemmaoracle/sdk": "^0.0.17",
33
+ "@lemmaoracle/spec": "workspace:*",
34
+ "@x402/core": "^2.9.0",
35
+ "@x402/evm": "^2.9.0",
36
+ "@x402/hono": "^2.9.0",
37
+ "hono": "^4.6.14",
38
+ "ramda": "^0.30.0",
39
+ "viem": "^2.21.0"
40
+ },
41
+ "devDependencies": {
42
+ "@cloudflare/workers-types": "^4.20241230.0",
43
+ "@types/ramda": "^0.30.0",
44
+ "circom2": "^0.2.22",
45
+ "circomlib": "^2.0.5",
46
+ "dotenv": "^16.4.7",
47
+ "dotenv-cli": "^11.0.0",
48
+ "poseidon-lite": "^0.3.0",
49
+ "snarkjs": "^0.7.5",
50
+ "tsx": "^4.19.0",
51
+ "typescript": "^5.7.3",
52
+ "vitest": "^2.0.0",
53
+ "wrangler": "^3.101.0"
54
+ }
55
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@lemmaoracle/x402",
3
+ "version": "0.1.1",
4
+ "description": "ZK-enabled x402 payment proofs for Lemma's disclosure.condition API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "tsc --build",
17
+ "build:circuit": "bash scripts/build.sh",
18
+ "dev": "tsc --watch",
19
+ "type-check": "tsc --noEmit",
20
+ "test": "vitest run && bash -c 'if [ ! -f \"build/payment_js/payment.wasm\" ]; then echo \"šŸ”§ Circuit not built. Building circuit first...\" && npm run build:circuit; fi && node circuits/payment.test.mjs'",
21
+ "test:vitest": "vitest run",
22
+ "test:watch": "vitest",
23
+ "test:circuit": "node circuits/payment.test.mjs",
24
+ "test:circuit:comprehensive": "node circuits/payment-comprehensive.test.mjs",
25
+ "deploy:worker": "wrangler deploy --config wrangler.toml",
26
+ "deploy": "dotenv -e ../../.env -- forge script ${SCRIPT:-scripts/DeployPaymentVerifier.s.sol} --broadcast",
27
+ "deploy:monadTestnet": "dotenv -e ../../.env -- forge script ${SCRIPT:-scripts/DeployPaymentVerifier.s.sol} --rpc-url monad_testnet --broadcast --verify",
28
+ "deploy:baseSepolia": "dotenv -e ../../.env -- forge script ${SCRIPT:-scripts/DeployPaymentVerifier.s.sol} --rpc-url base_sepolia --broadcast --verify",
29
+ "register": "tsx scripts/register-circuit.ts"
30
+ },
31
+ "dependencies": {
32
+ "@lemmaoracle/sdk": "workspace:*",
33
+ "@lemmaoracle/spec": "workspace:*",
34
+ "@x402/core": "^2.9.0",
35
+ "@x402/evm": "^2.9.0",
36
+ "@x402/hono": "^2.9.0",
37
+ "hono": "^4.6.14",
38
+ "ramda": "^0.30.0",
39
+ "viem": "^2.21.0"
40
+ },
41
+ "devDependencies": {
42
+ "@cloudflare/workers-types": "^4.20241230.0",
43
+ "@types/ramda": "^0.30.0",
44
+ "circom2": "^0.2.22",
45
+ "circomlib": "^2.0.5",
46
+ "dotenv": "^16.4.7",
47
+ "dotenv-cli": "^11.0.0",
48
+ "poseidon-lite": "^0.3.0",
49
+ "snarkjs": "^0.7.5",
50
+ "tsx": "^4.19.0",
51
+ "typescript": "^5.7.3",
52
+ "vitest": "^2.0.0",
53
+ "wrangler": "^3.101.0"
54
+ }
55
+ }
@@ -0,0 +1,18 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.24;
3
+
4
+ import {Script, console} from "forge-std/Script.sol";
5
+ import {Groth16Verifier} from "../build/PaymentVerifier.sol";
6
+
7
+ contract DeployPaymentVerifier is Script {
8
+ function run() external returns (Groth16Verifier) {
9
+ uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
10
+
11
+ vm.startBroadcast(deployerPrivateKey);
12
+ Groth16Verifier verifier = new Groth16Verifier();
13
+ vm.stopBroadcast();
14
+
15
+ console.log("Groth16Verifier (PaymentVerifier) deployed at:", address(verifier));
16
+ return verifier;
17
+ }
18
+ }
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+ # Build script for x402 payment circuit
3
+ # Compiles circuit → trusted setup → export verifier contract
4
+ set -euo pipefail
5
+
6
+ CIRCUIT="circuits/payment.circom"
7
+ BUILD_DIR="build"
8
+ PTAU="build/pot14_final.ptau"
9
+ LIBS_DIR="$BUILD_DIR/libs"
10
+
11
+ mkdir -p "$BUILD_DIR"
12
+
13
+ # circom2 (WASM) cannot follow symlinks, which breaks with pnpm's symlinked
14
+ # node_modules. Copy circomlib into the build directory as real files.
15
+ rm -rf "$LIBS_DIR"
16
+ mkdir -p "$LIBS_DIR"
17
+ cp -rL node_modules/circomlib "$LIBS_DIR/circomlib"
18
+
19
+ echo "1/5 Compiling x402 payment circuit..."
20
+ npx circom2 "$CIRCUIT" --r1cs --wasm --sym -o "$BUILD_DIR" -l "$LIBS_DIR"
21
+
22
+ echo "2/5 Downloading Powers of Tau (Hermez, 14)..."
23
+ if [ ! -f "$PTAU" ]; then
24
+ curl -L -o "$PTAU" \
25
+ "https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_14.ptau"
26
+ fi
27
+
28
+ echo "3/5 Groth16 setup..."
29
+ npx snarkjs groth16 setup \
30
+ "$BUILD_DIR/payment.r1cs" \
31
+ "$PTAU" \
32
+ "$BUILD_DIR/payment_0000.zkey"
33
+
34
+ echo "4/5 Contributing to phase 2 (demo only — not secure for production)..."
35
+ echo "demo_entropy_x402_lemma_2026" | npx snarkjs zkey contribute \
36
+ "$BUILD_DIR/payment_0000.zkey" \
37
+ "$BUILD_DIR/payment_final.zkey" \
38
+ --name="Demo contribution x402 payment" -v
39
+
40
+ echo "5/5 Exporting verification key and Solidity verifier..."
41
+ # Export verification key (for off-chain verification)
42
+ npx snarkjs zkey export verificationkey \
43
+ "$BUILD_DIR/payment_final.zkey" \
44
+ "$BUILD_DIR/verification_key.json"
45
+
46
+ # Export Solidity verifier contract
47
+ npx snarkjs zkey export solidityverifier \
48
+ "$BUILD_DIR/payment_final.zkey" \
49
+ "$BUILD_DIR/PaymentVerifier.sol"
50
+
51
+ echo ""
52
+ echo "āœ… Build complete"
53
+ echo " WASM : $BUILD_DIR/payment_js/payment.wasm"
54
+ echo " zkey : $BUILD_DIR/payment_final.zkey"
55
+ echo " Verification key: $BUILD_DIR/verification_key.json"
56
+ echo " Verifier contract: $BUILD_DIR/PaymentVerifier.sol"
57
+ echo ""
58
+ echo "Next steps:"
59
+ echo " 1. Upload wasm + zkey to IPFS"
60
+ echo " 2. Register with Lemma: circuits.register(client, { circuitId: 'x402-payment-v1', ... })"
61
+ echo ""
@@ -0,0 +1,65 @@
1
+ #!/bin/bash
2
+ # Deploy PaymentVerifier contract to Monad Testnet
3
+
4
+ set -e
5
+
6
+ echo "šŸš€ Deploying PaymentVerifier to Monad Testnet..."
7
+
8
+ # Load environment variables
9
+ if [ -f .env ]; then
10
+ export $(cat .env | grep -v '^#' | xargs)
11
+ fi
12
+
13
+ # Check required environment variables
14
+ if [ -z "$PRIVATE_KEY" ]; then
15
+ echo "āŒ PRIVATE_KEY is not set"
16
+ exit 1
17
+ fi
18
+
19
+ if [ -z "$RPC_URL" ]; then
20
+ RPC_URL="https://testnet-rpc.monad.xyz"
21
+ echo "āš ļø RPC_URL not set, using default: $RPC_URL"
22
+ fi
23
+
24
+ # Check if contract exists
25
+ if [ ! -f "build/PaymentVerifier.sol" ]; then
26
+ echo "āŒ PaymentVerifier.sol not found. Run build.sh first."
27
+ exit 1
28
+ fi
29
+
30
+ # Deploy contract
31
+ echo "šŸ“„ Deploying PaymentVerifier..."
32
+ DEPLOY_OUTPUT=$(forge create \
33
+ --rpc-url "$RPC_URL" \
34
+ --private-key "$PRIVATE_KEY" \
35
+ --legacy \
36
+ "build/PaymentVerifier.sol:PaymentVerifier")
37
+
38
+ echo "$DEPLOY_OUTPUT"
39
+
40
+ # Extract contract address
41
+ CONTRACT_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -o "Deployed to: 0x[0-9a-fA-F]\{40\}" | cut -d' ' -f3)
42
+
43
+ if [ -n "$CONTRACT_ADDRESS" ]; then
44
+ echo "āœ… Contract deployed successfully!"
45
+ echo "šŸ“ Contract address: $CONTRACT_ADDRESS"
46
+
47
+ # Save to environment file
48
+ echo "VERIFIER_CONTRACT=$CONTRACT_ADDRESS" > .verifier.env
49
+ echo "āœ… Saved to .verifier.env"
50
+
51
+ # Verify on Etherscan if API key is available
52
+ if [ -n "$ETHERSCAN_API_KEY" ]; then
53
+ echo "šŸ” Verifying on Etherscan..."
54
+ forge verify-contract \
55
+ --chain-id 10143 \
56
+ --etherscan-api-key "$ETHERSCAN_API_KEY" \
57
+ --compiler-version v0.8.28+commit.5fe4bb1d \
58
+ --num-of-optimizations 200 \
59
+ "$CONTRACT_ADDRESS" \
60
+ "build/PaymentVerifier.sol:PaymentVerifier" || echo "āš ļø Verification failed or skipped"
61
+ fi
62
+ else
63
+ echo "āŒ Failed to extract contract address"
64
+ exit 1
65
+ fi
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Fix G2 point encoding bug in snarkjs-generated verifier contracts
4
+ *
5
+ * This script swaps the coordinate order in G2 points to match EIP-197 compatibility.
6
+ * Required for snarkjs-generated verifiers to work with Ethereum.
7
+ */
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+
12
+ const VERIFIER_PATH = path.join(process.cwd(), 'build', 'PaymentVerifier.sol');
13
+
14
+ function fixG2Encoding(content) {
15
+ // Pattern to match G2 points in the verifier
16
+ // Looking for lines like: vk.gamma[0] = Pairing.G2Point([...], [...]);
17
+ const g2PointPattern = /(vk\.(gamma|gamma_2|gamma_abc\[0\]) = Pairing\.G2Point\()\[(0x[0-9a-fA-F, ]+)\],\s*\[(0x[0-9a-fA-F, ]+)\]\);/g;
18
+
19
+ let fixedContent = content;
20
+ let replacements = 0;
21
+
22
+ // Find and fix all G2 points
23
+ fixedContent = fixedContent.replace(g2PointPattern, (match, prefix, pointType, xCoord, yCoord) => {
24
+ replacements++;
25
+ console.log(`šŸ”§ Fixing ${pointType} G2 point (swap coordinates)`);
26
+ // Swap the coordinates
27
+ return `${prefix}[${yCoord}], [${xCoord}]);`;
28
+ });
29
+
30
+ if (replacements > 0) {
31
+ console.log(`āœ… Fixed ${replacements} G2 point(s)`);
32
+ } else {
33
+ console.log('āš ļø No G2 points found to fix');
34
+ }
35
+
36
+ return fixedContent;
37
+ }
38
+
39
+ function main() {
40
+ console.log(`šŸ” Checking verifier: ${VERIFIER_PATH}`);
41
+
42
+ if (!fs.existsSync(VERIFIER_PATH)) {
43
+ console.error(`āŒ Verifier file not found: ${VERIFIER_PATH}`);
44
+ console.error(' Run build.sh first to generate the verifier.');
45
+ process.exit(1);
46
+ }
47
+
48
+ // Read the verifier contract
49
+ const content = fs.readFileSync(VERIFIER_PATH, 'utf8');
50
+
51
+ // Fix G2 encoding
52
+ const fixedContent = fixG2Encoding(content);
53
+
54
+ // Write back if changes were made
55
+ if (content !== fixedContent) {
56
+ fs.writeFileSync(VERIFIER_PATH, fixedContent, 'utf8');
57
+ console.log('āœ… Verifier contract fixed and saved.');
58
+ } else {
59
+ console.log('āœ… No changes needed.');
60
+ }
61
+ }
62
+
63
+ // Run the script
64
+ main();
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Register x402 payment circuit with Lemma
4
+ *
5
+ * This script:
6
+ * 1. Uploads payment circuit WASM and zkey to Pinata
7
+ * 2. Registers the circuit with Lemma SDK using the deployed verifier contract
8
+ */
9
+
10
+ import { create, circuits } from "@lemmaoracle/sdk";
11
+ import type { LemmaClient, CircuitMeta } from "@lemmaoracle/spec";
12
+ import dotenv from "dotenv";
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
+ const PROJECT_ROOT = path.resolve(__dirname, "../../..");
19
+
20
+ // Load environment variables
21
+ dotenv.config({ path: path.join(PROJECT_ROOT, ".env") });
22
+
23
+ const LEMMA_API_KEY = process.env.LEMMA_API_KEY;
24
+ const PINATA_API_KEY = process.env.PINATA_API_KEY;
25
+ const PINATA_SECRET_API_KEY = process.env.PINATA_SECRET_API_KEY;
26
+
27
+ // Verifier contract address from deployment (Monad Testnet)
28
+ const VERIFIER_ADDRESS = "0x851b33e46fc1ded8f752d1f2f26a9c58afde8815";
29
+ const CHAIN_ID = 10143; // Monad Testnet
30
+
31
+ /* ------------------------------------------------------------------ */
32
+ /* Pinata Upload Functions */
33
+ /* ------------------------------------------------------------------ */
34
+
35
+ type PinataUploadResponse = Readonly<{
36
+ readonly IpfsHash: string;
37
+ readonly PinSize: number;
38
+ readonly Timestamp: string;
39
+ readonly isDuplicate?: boolean;
40
+ }>;
41
+
42
+ const uploadToPinata = (filePath: string, fileName: string): Promise<PinataUploadResponse> => {
43
+ const formData = new FormData();
44
+ const file = fs.readFileSync(filePath);
45
+ const blob = new Blob([file]);
46
+ formData.append("file", blob, fileName);
47
+
48
+ const metadata = JSON.stringify({
49
+ name: fileName,
50
+ keyvalues: {
51
+ project: "lemma-x402",
52
+ circuit: "payment",
53
+ timestamp: Date.now().toString(),
54
+ },
55
+ });
56
+ formData.append("pinataMetadata", metadata);
57
+
58
+ const options = JSON.stringify({ cidVersion: 0 });
59
+ formData.append("pinataOptions", options);
60
+
61
+ return fetch("https://api.pinata.cloud/pinning/pinFileToIPFS", {
62
+ method: "POST",
63
+ headers: {
64
+ pinata_api_key: PINATA_API_KEY!,
65
+ pinata_secret_api_key: PINATA_SECRET_API_KEY!,
66
+ },
67
+ body: formData,
68
+ })
69
+ .then((res: Response) =>
70
+ res.ok ? res.json() : Promise.reject(new Error(`Pinata upload failed: ${res.status}`)),
71
+ )
72
+ .then((data: unknown) => data as PinataUploadResponse);
73
+ };
74
+
75
+ const uploadFileToPinata = (filePath: string, fileName: string): Promise<string> => {
76
+ if (!PINATA_API_KEY || !PINATA_SECRET_API_KEY) {
77
+ return Promise.reject(
78
+ new Error("PINATA_API_KEY and PINATA_SECRET_API_KEY environment variables are required"),
79
+ );
80
+ }
81
+ return uploadToPinata(filePath, fileName)
82
+ .then((response) => `ipfs://${response.IpfsHash}`)
83
+ .catch((error) => Promise.reject(new Error(`Failed to upload ${fileName}: ${error.message}`)));
84
+ };
85
+
86
+ /* ------------------------------------------------------------------ */
87
+ /* File Validation Functions */
88
+ /* ------------------------------------------------------------------ */
89
+
90
+ const validateEnvironment = (): Promise<void> => {
91
+ if (!LEMMA_API_KEY || !PINATA_API_KEY || !PINATA_SECRET_API_KEY) {
92
+ return Promise.reject(
93
+ new Error(
94
+ "Missing required environment variables: LEMMA_API_KEY, PINATA_API_KEY, PINATA_SECRET_API_KEY",
95
+ ),
96
+ );
97
+ }
98
+ return Promise.resolve();
99
+ };
100
+
101
+ const checkFileExists = (filePath: string): Promise<void> => {
102
+ if (fs.existsSync(filePath)) {
103
+ return Promise.resolve();
104
+ }
105
+ return Promise.reject(new Error(`File not found: ${filePath}`));
106
+ };
107
+
108
+ /* ------------------------------------------------------------------ */
109
+ /* Circuit Registration */
110
+ /* ------------------------------------------------------------------ */
111
+
112
+ const createLemmaClient = (): LemmaClient =>
113
+ create({
114
+ apiBase: "https://workers.lemma.workers.dev",
115
+ apiKey: LEMMA_API_KEY!,
116
+ });
117
+
118
+ const registerCircuit = (client: LemmaClient, circuitMeta: CircuitMeta): Promise<CircuitMeta> =>
119
+ circuits.register(client, circuitMeta);
120
+
121
+ const buildCircuitMeta = (wasmIpfsUrl: string, zkeyIpfsUrl: string): CircuitMeta => ({
122
+ circuitId: "x402-payment-v1",
123
+ schema: "passthrough-v1",
124
+ description: "x402 payment circuit for Monad Testnet",
125
+ inputs: ["amount", "recipient", "nonce"],
126
+ verifiers: [
127
+ {
128
+ type: "onchain",
129
+ address: VERIFIER_ADDRESS,
130
+ chainId: CHAIN_ID,
131
+ alg: "groth16-bn254-snarkjs",
132
+ },
133
+ ],
134
+ artifact: {
135
+ location: {
136
+ type: "ipfs",
137
+ wasm: wasmIpfsUrl,
138
+ zkey: zkeyIpfsUrl,
139
+ },
140
+ },
141
+ metadata: {
142
+ network: "monad-testnet",
143
+ chainId: CHAIN_ID,
144
+ version: "1.0",
145
+ deploymentTx: "0x365504aa2131a5e3f046dbbd3f929ebae17d3f78a21cea9d52742252bd9b33c2",
146
+ deploymentBlock: 0x17cf6e9,
147
+ circuitType: "payment",
148
+ },
149
+ });
150
+
151
+ /* ------------------------------------------------------------------ */
152
+ /* Main Execution Pipeline */
153
+ /* ------------------------------------------------------------------ */
154
+
155
+ const main = async (): Promise<void> => {
156
+ try {
157
+ console.log("šŸš€ Starting x402 payment circuit registration...");
158
+ await validateEnvironment();
159
+
160
+ const wasmPath = path.join(PROJECT_ROOT, "packages/x402/build/payment_js/payment.wasm");
161
+ const zkeyPath = path.join(PROJECT_ROOT, "packages/x402/build/payment_final.zkey");
162
+
163
+ console.log("1. Checking artifact files...");
164
+ await Promise.all([checkFileExists(wasmPath), checkFileExists(zkeyPath)]);
165
+
166
+ console.log("2. Uploading artifacts to Pinata...");
167
+ const [wasmIpfsUrl, zkeyIpfsUrl] = await Promise.all([
168
+ uploadFileToPinata(wasmPath, "payment.wasm"),
169
+ uploadFileToPinata(zkeyPath, "payment_final.zkey"),
170
+ ]);
171
+
172
+ console.log("3. Registering circuit with Lemma...");
173
+ const client = createLemmaClient();
174
+ const circuitMeta = buildCircuitMeta(wasmIpfsUrl, zkeyIpfsUrl);
175
+ const registeredCircuit = await registerCircuit(client, circuitMeta);
176
+
177
+ console.log("\nāœ… Circuit registered successfully!");
178
+ console.log(`šŸ“ Circuit ID: ${registeredCircuit.circuitId}`);
179
+ console.log(`šŸ”— Schema: ${registeredCircuit.schema}`);
180
+ console.log(`šŸ¢ Verifier: ${VERIFIER_ADDRESS} (Chain: ${CHAIN_ID})`);
181
+ console.log(`šŸ“¦ WASM IPFS: ${wasmIpfsUrl}`);
182
+ console.log(`šŸ“¦ zKey IPFS: ${zkeyIpfsUrl}`);
183
+ console.log("\nšŸŽ‰ x402 payment circuit is now ready for use!");
184
+ } catch (error: unknown) {
185
+ console.error("\nāŒ Error:", error instanceof Error ? error.message : String(error));
186
+
187
+ // Check if circuit already exists
188
+ if (
189
+ error instanceof Error &&
190
+ (error.message.includes("already exists") || error.message.includes("409"))
191
+ ) {
192
+ console.log("\nā„¹ļø Circuit may already be registered. Checking...");
193
+ try {
194
+ const client = createLemmaClient();
195
+ const existingCircuit = await circuits.getById(client, "x402-payment-v1");
196
+ console.log(" āœ… Circuit already exists:", existingCircuit.circuitId);
197
+ console.log(" šŸ”— Existing verifier:", existingCircuit.verifiers?.[0]?.address);
198
+ console.log(" šŸ“¦ Existing WASM IPFS:", existingCircuit.artifact?.location.wasm);
199
+ } catch (checkError) {
200
+ console.error(
201
+ " āŒ Circuit check failed:",
202
+ checkError instanceof Error ? checkError.message : String(checkError),
203
+ );
204
+ process.exit(1);
205
+ }
206
+ } else {
207
+ process.exit(1);
208
+ }
209
+ }
210
+ };
211
+
212
+ // Execute main function
213
+ main();