x402z-server 0.0.2 → 0.0.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.
package/dist/index.d.mts CHANGED
@@ -3,6 +3,7 @@ export * from '@x402/core/types';
3
3
  import { x402ResourceServer } from '@x402/core/server';
4
4
  export { x402ResourceServer } from '@x402/core/server';
5
5
  import * as http from 'http';
6
+ import { RelayerSigner, RelayerInstance } from 'x402z-shared';
6
7
  export { CompiledRoute, DynamicPayTo, DynamicPrice, FacilitatorClient, FacilitatorConfig, HTTPAdapter, HTTPFacilitatorClient, HTTPProcessResult, HTTPRequestContext, HTTPResponseInstructions, PaymentOption, PaywallConfig, PaywallProvider, ProcessSettleFailureResponse, ProcessSettleResultResponse, ProcessSettleSuccessResponse, RouteConfig, RouteConfigurationError, RouteValidationError, RoutesConfig, UnpaidResponseBody, UnpaidResponseResult, x402HTTPResourceServer } from '@x402/core/http';
7
8
 
8
9
  type ConfidentialServerNetworkConfig = {
@@ -60,6 +61,8 @@ type X402zServerConfig = ConfidentialServerRegisterConfig & {
60
61
  facilitatorUrl: string;
61
62
  routes: Record<string, X402zRouteConfig>;
62
63
  onPaid: X402zRouteHandler;
64
+ signer: RelayerSigner;
65
+ relayer: RelayerInstance;
63
66
  debug?: boolean;
64
67
  };
65
68
  declare function createX402zServer(config: X402zServerConfig): Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>>;
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from '@x402/core/types';
3
3
  import { x402ResourceServer } from '@x402/core/server';
4
4
  export { x402ResourceServer } from '@x402/core/server';
5
5
  import * as http from 'http';
6
+ import { RelayerSigner, RelayerInstance } from 'x402z-shared';
6
7
  export { CompiledRoute, DynamicPayTo, DynamicPrice, FacilitatorClient, FacilitatorConfig, HTTPAdapter, HTTPFacilitatorClient, HTTPProcessResult, HTTPRequestContext, HTTPResponseInstructions, PaymentOption, PaywallConfig, PaywallProvider, ProcessSettleFailureResponse, ProcessSettleResultResponse, ProcessSettleSuccessResponse, RouteConfig, RouteConfigurationError, RouteValidationError, RoutesConfig, UnpaidResponseBody, UnpaidResponseResult, x402HTTPResourceServer } from '@x402/core/http';
7
8
 
8
9
  type ConfidentialServerNetworkConfig = {
@@ -60,6 +61,8 @@ type X402zServerConfig = ConfidentialServerRegisterConfig & {
60
61
  facilitatorUrl: string;
61
62
  routes: Record<string, X402zRouteConfig>;
62
63
  onPaid: X402zRouteHandler;
64
+ signer: RelayerSigner;
65
+ relayer: RelayerInstance;
63
66
  debug?: boolean;
64
67
  };
65
68
  declare function createX402zServer(config: X402zServerConfig): Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>>;
package/dist/index.js CHANGED
@@ -124,6 +124,15 @@ var import_node_url = require("url");
124
124
  var import_server = require("@x402/core/server");
125
125
  var import_http = require("@x402/core/http");
126
126
  var import_http2 = require("@x402/core/http");
127
+ var import_x402z_shared = require("x402z-shared");
128
+ var import_viem = require("viem");
129
+ function getRelayerRpcUrl(relayer) {
130
+ const network = relayer.network;
131
+ if (typeof network === "string") {
132
+ return network;
133
+ }
134
+ throw new Error("relayer.network must be a string RPC URL");
135
+ }
127
136
  function buildAdapter(req) {
128
137
  const url = new import_node_url.URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
129
138
  return {
@@ -148,6 +157,8 @@ async function createX402zServer(config) {
148
157
  const facilitatorClient = new import_http2.HTTPFacilitatorClient({ url: config.facilitatorUrl });
149
158
  const resourceServer = new import_server.x402ResourceServer(facilitatorClient);
150
159
  registerConfidentialEvmScheme(resourceServer, config);
160
+ const relayer = config.relayer;
161
+ const rpcUrl = getRelayerRpcUrl(relayer);
151
162
  const routes = {};
152
163
  for (const [path, route] of Object.entries(config.routes)) {
153
164
  routes[path] = {
@@ -188,6 +199,50 @@ async function createX402zServer(config) {
188
199
  console.log(`[server] ${method} ${path} -> 500 settlement_failed`);
189
200
  return;
190
201
  }
202
+ try {
203
+ const observerClient = (0, import_viem.createPublicClient)({
204
+ transport: (0, import_viem.http)(rpcUrl)
205
+ });
206
+ const payTo = (0, import_viem.getAddress)(result.paymentRequirements.payTo);
207
+ const observer = await observerClient.readContract({
208
+ address: (0, import_viem.getAddress)(result.paymentRequirements.asset),
209
+ abi: import_x402z_shared.confidentialTokenAbi,
210
+ functionName: "observer",
211
+ args: [payTo]
212
+ });
213
+ const signerAddress = (0, import_viem.getAddress)(config.signer.address);
214
+ if (!observer || !(0, import_viem.isAddressEqual)(observer, signerAddress)) {
215
+ res.writeHead(500, { "Content-Type": "application/json" });
216
+ res.end(JSON.stringify({ error: "observer_required" }));
217
+ console.log(`[server] ${method} ${path} -> 500 observer_required`);
218
+ return;
219
+ }
220
+ const transfers = await (0, import_x402z_shared.viewConfidentialTransferAmounts)({
221
+ rpcUrl,
222
+ tokenAddress: result.paymentRequirements.asset,
223
+ txHash: settle.transaction,
224
+ from: settle.payer,
225
+ to: result.paymentRequirements.payTo,
226
+ relayer,
227
+ signer: config.signer
228
+ });
229
+ const expected = BigInt(result.paymentRequirements.amount);
230
+ const matched = transfers.some((transfer) => transfer.amount === expected);
231
+ if (!matched) {
232
+ res.writeHead(500, { "Content-Type": "application/json" });
233
+ res.end(JSON.stringify({ error: "settlement_amount_mismatch" }));
234
+ console.log(`[server] ${method} ${path} -> 500 settlement_amount_mismatch`);
235
+ return;
236
+ }
237
+ } catch (error) {
238
+ res.writeHead(500, { "Content-Type": "application/json" });
239
+ res.end(JSON.stringify({ error: "settlement_verification_failed" }));
240
+ console.log(`[server] ${method} ${path} -> 500 settlement_verification_failed`);
241
+ if (debugEnabled) {
242
+ console.debug("[x402z-server] settlement verification error", error);
243
+ }
244
+ return;
245
+ }
191
246
  const payload = await config.onPaid({
192
247
  paymentRequirements: result.paymentRequirements,
193
248
  settleHeaders: settle.headers
package/dist/index.mjs CHANGED
@@ -93,6 +93,15 @@ import { URL } from "url";
93
93
  import { x402ResourceServer } from "@x402/core/server";
94
94
  import { x402HTTPResourceServer } from "@x402/core/http";
95
95
  import { HTTPFacilitatorClient } from "@x402/core/http";
96
+ import { confidentialTokenAbi, viewConfidentialTransferAmounts } from "x402z-shared";
97
+ import { createPublicClient, getAddress, http, isAddressEqual } from "viem";
98
+ function getRelayerRpcUrl(relayer) {
99
+ const network = relayer.network;
100
+ if (typeof network === "string") {
101
+ return network;
102
+ }
103
+ throw new Error("relayer.network must be a string RPC URL");
104
+ }
96
105
  function buildAdapter(req) {
97
106
  const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
98
107
  return {
@@ -117,6 +126,8 @@ async function createX402zServer(config) {
117
126
  const facilitatorClient = new HTTPFacilitatorClient({ url: config.facilitatorUrl });
118
127
  const resourceServer = new x402ResourceServer(facilitatorClient);
119
128
  registerConfidentialEvmScheme(resourceServer, config);
129
+ const relayer = config.relayer;
130
+ const rpcUrl = getRelayerRpcUrl(relayer);
120
131
  const routes = {};
121
132
  for (const [path, route] of Object.entries(config.routes)) {
122
133
  routes[path] = {
@@ -157,6 +168,50 @@ async function createX402zServer(config) {
157
168
  console.log(`[server] ${method} ${path} -> 500 settlement_failed`);
158
169
  return;
159
170
  }
171
+ try {
172
+ const observerClient = createPublicClient({
173
+ transport: http(rpcUrl)
174
+ });
175
+ const payTo = getAddress(result.paymentRequirements.payTo);
176
+ const observer = await observerClient.readContract({
177
+ address: getAddress(result.paymentRequirements.asset),
178
+ abi: confidentialTokenAbi,
179
+ functionName: "observer",
180
+ args: [payTo]
181
+ });
182
+ const signerAddress = getAddress(config.signer.address);
183
+ if (!observer || !isAddressEqual(observer, signerAddress)) {
184
+ res.writeHead(500, { "Content-Type": "application/json" });
185
+ res.end(JSON.stringify({ error: "observer_required" }));
186
+ console.log(`[server] ${method} ${path} -> 500 observer_required`);
187
+ return;
188
+ }
189
+ const transfers = await viewConfidentialTransferAmounts({
190
+ rpcUrl,
191
+ tokenAddress: result.paymentRequirements.asset,
192
+ txHash: settle.transaction,
193
+ from: settle.payer,
194
+ to: result.paymentRequirements.payTo,
195
+ relayer,
196
+ signer: config.signer
197
+ });
198
+ const expected = BigInt(result.paymentRequirements.amount);
199
+ const matched = transfers.some((transfer) => transfer.amount === expected);
200
+ if (!matched) {
201
+ res.writeHead(500, { "Content-Type": "application/json" });
202
+ res.end(JSON.stringify({ error: "settlement_amount_mismatch" }));
203
+ console.log(`[server] ${method} ${path} -> 500 settlement_amount_mismatch`);
204
+ return;
205
+ }
206
+ } catch (error) {
207
+ res.writeHead(500, { "Content-Type": "application/json" });
208
+ res.end(JSON.stringify({ error: "settlement_verification_failed" }));
209
+ console.log(`[server] ${method} ${path} -> 500 settlement_verification_failed`);
210
+ if (debugEnabled) {
211
+ console.debug("[x402z-server] settlement verification error", error);
212
+ }
213
+ return;
214
+ }
160
215
  const payload = await config.onPaid({
161
216
  paymentRequirements: result.paymentRequirements,
162
217
  settleHeaders: settle.headers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402z-server",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -10,7 +10,7 @@
10
10
  "dependencies": {
11
11
  "@x402/core": "^2.0.0",
12
12
  "viem": "^2.43.3",
13
- "x402z-shared": "0.0.2"
13
+ "x402z-shared": "0.0.3"
14
14
  },
15
15
  "devDependencies": {
16
16
  "jest": "^29.7.0",