Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy-server-og-evm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
env:
ECS_CLUSTER: MemChat
ECS_SERVICE: memchat-facilitator-x402-og-evm
ECR_REPOSITORY: memchat/facilitator-x402-og-evm
ECR_REPOSITORY: memchat/facilitator-x402
IMAGE_TAG: latest
AWS_REGION: us-east-2

Expand Down
8 changes: 1 addition & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY typescript/package.json ./typescript/
COPY typescript/packages/core/package.json ./typescript/packages/core/
COPY typescript/packages/extensions/package.json ./typescript/packages/extensions/
COPY typescript/packages/mcp/package.json ./typescript/packages/mcp/
COPY typescript/packages/mechanisms/evm/package.json ./typescript/packages/mechanisms/evm/
COPY typescript/packages/mechanisms/svm/package.json ./typescript/packages/mechanisms/svm/
COPY typescript/packages/http/next/package.json ./typescript/packages/http/next/
COPY typescript/packages/http/express/package.json ./typescript/packages/http/express/
COPY typescript/packages/http/fetch/package.json ./typescript/packages/http/fetch/
Expand All @@ -30,13 +28,10 @@ RUN pnpm install --frozen-lockfile
# Copy source code
COPY . .

# Build all packages
# We assume 'pnpm build' at root builds all workspace packages
RUN pnpm --filter @x402/core build && \
pnpm --filter @x402/evm build && \
pnpm --filter @x402/svm build && \
pnpm --filter @x402/extensions build && \
pnpm build
pnpm exec tsc --noCheck

# Remove development dependencies
RUN pnpm prune --prod
Expand All @@ -58,4 +53,3 @@ COPY --from=builder /app/typescript/packages ./typescript/packages
EXPOSE 3002

CMD ["node", "dist/all_networks.js"]

82 changes: 67 additions & 15 deletions all_networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
import { randomUUID } from "node:crypto";
import { type Server } from "node:http";
import { getAddress, isAddress } from "viem";
import {
debugLog,
summarizeDataSettlementJob,
summarizeError,
summarizePaymentPayload,
summarizePaymentRequirements,
summarizeVerifyResponse,
} from "./logging.js";
import { incrementMetric } from "./metrics.js";
import {
createBullMqConnection,
Expand All @@ -29,7 +37,11 @@
type PaymentSettlementJobData,
type SettlementApiJobResponse,
} from "./all_networks_types_helpers.js";
import { type PaymentPayload, type PaymentRequirements, type VerifyResponse } from "@x402/core/types";
import {
type PaymentPayload,
type PaymentRequirements,
type VerifyResponse,
} from "@x402/core/types";

const app = express();
app.use(express.json());
Expand All @@ -52,7 +64,6 @@
}
})();


const paymentQueue = new Queue<PaymentSettlementJobData>(PAYMENT_QUEUE_NAME, {
connection,
defaultJobOptions: {
Expand Down Expand Up @@ -154,6 +165,12 @@
},
);

console.log("[api] Payment settlement job enqueued", {
jobId: paymentJobId,
...summarizePaymentRequirements(args.paymentRequirements),
...summarizePaymentPayload(args.paymentPayload),
});

return toJobResponse(PAYMENT_QUEUE_NAME, paymentJob);
}

Expand All @@ -170,26 +187,29 @@
await processPrivateSettlement();
return null;
}

if (!parsedSettlementHeader) {
throw new Error("Missing x-settlement-type header");
}

debugLog("[api][debug] Parsed data settlement job", parsedSettlementHeader);

const settlementJobId = `settlement-${randomUUID()}`;
const settlementJob = await dataSettlementQueue.add(
"data-settlement",
parsedSettlementHeader,
{
jobId: settlementJobId,
},
);
const settlementJob = await dataSettlementQueue.add("data-settlement", parsedSettlementHeader, {
jobId: settlementJobId,
});

console.log("[api] Data settlement job enqueued", {
jobId: settlementJobId,
...summarizeDataSettlementJob(parsedSettlementHeader),
});

return toJobResponse(DATA_SETTLEMENT_QUEUE_NAME, settlementJob);
}

app.post("/verify", async (req, res) => {
incrementMetric("api.request.count", ["route:/verify", "method:POST"]);
try {

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
const { paymentPayload, paymentRequirements } = req.body as {
paymentPayload: PaymentPayload;
paymentRequirements: PaymentRequirements;
Expand All @@ -201,17 +221,27 @@
});
}

console.log("[api] /verify request received", {
...summarizePaymentRequirements(paymentRequirements),
...summarizePaymentPayload(paymentPayload),
});
debugLog("[api][debug] /verify request body", req.body);

const response: VerifyResponse = await facilitator.verify(paymentPayload, paymentRequirements);
console.log("[api] /verify request succeeded", {
...summarizePaymentRequirements(paymentRequirements),
...summarizeVerifyResponse(response),
});
debugLog("[api][debug] /verify response", response);
res.json(response);
} catch (error) {
console.error("Verify error:", error);
console.error("[api] /verify request failed", summarizeError(error));
res.status(500).json({
error: error instanceof Error ? error.message : "Unknown error",
});
}
});


app.post("/settle", async (req, res) => {
incrementMetric("api.request.count", ["route:/settle", "method:POST"]);
try {
Expand All @@ -226,13 +256,19 @@
});
}

console.log("[api] /settle request received", {
...summarizePaymentRequirements(paymentRequirements),
...summarizePaymentPayload(paymentPayload),
});
debugLog("[api][debug] /settle request body", req.body);

const paymentJob = await enqueuePaymentSettlementJob({
paymentPayload,
paymentRequirements,
});
return res.status(202).json({ paymentJob });
} catch (error) {
console.error("Settle enqueue error:", error);
console.error("[api] /settle request failed", summarizeError(error));
if (isSettlementError(error)) {
return res.status(400).json({
error: error.message,
Expand All @@ -256,6 +292,14 @@
}

const settlementDataHeader = normalizeHeaderValue(req.get("x-settlement-data") || undefined);
console.log("[api] /settle_data request received", {
settlementType: settlementTypeHeader,
hasSettlementDataHeader: Boolean(settlementDataHeader),
});
debugLog("[api][debug] /settle_data headers", {
settlementTypeHeader,
settlementDataHeader,
});
const settlementJob = await enqueueDataSettlementJob({
settlementTypeHeader,
settlementDataHeader,
Expand All @@ -270,7 +314,7 @@

return res.status(202).json({ settlementJob });
} catch (error) {
console.error("Settle data enqueue error:", error);
console.error("[api] /settle_data request failed", summarizeError(error));
if (isSettlementError(error)) {
return res.status(400).json({
error: error.message,
Expand Down Expand Up @@ -401,7 +445,13 @@
});

app.get("/health", (_req, res) => {
res.json({ status: "ok" });
const supported = facilitator.getSupported();
res.json({
status: "ok",
supportedKinds: supported.kinds,
extensions: supported.extensions,
signers: supported.signers,
});
});

let httpServer: Server | null = null;
Expand Down Expand Up @@ -441,8 +491,10 @@
});

httpServer = app.listen(parseInt(PORT, 10), () => {
const supported = facilitator.getSupported();
console.log(`🚀 All Networks API listening on http://localhost:${PORT}`);
console.log(` Supported networks: ${facilitator.getSupported().kinds.map(k => k.network).join(", ")}`);
console.log(` Supported networks: ${supported.kinds.map(k => k.network).join(", ")}`);
console.log(` Supported extensions: ${supported.extensions.join(", ") || "(none)"}`);
console.log(` Payment queue: ${PAYMENT_QUEUE_NAME}`);
console.log(` Data settlement queue: ${DATA_SETTLEMENT_QUEUE_NAME}`);
console.log();
Expand Down
Loading
Loading