Skip to content

Commit cb6a7c9

Browse files
authored
feat: add 'test webhook' route (#768)
1 parent 68b3ed1 commit cb6a7c9

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

src/server/routes/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ import { createWebhookRoute } from "./webhooks/create";
109109
import { getWebhooksEventTypes } from "./webhooks/events";
110110
import { getAllWebhooksData } from "./webhooks/getAll";
111111
import { revokeWebhook } from "./webhooks/revoke";
112+
import { testWebhookRoute } from "./webhooks/test";
112113

113114
export const withRoutes = async (fastify: FastifyInstance) => {
114115
// Backend Wallets
@@ -158,6 +159,7 @@ export const withRoutes = async (fastify: FastifyInstance) => {
158159
await fastify.register(createWebhookRoute);
159160
await fastify.register(revokeWebhook);
160161
await fastify.register(getWebhooksEventTypes);
162+
await fastify.register(testWebhookRoute);
161163

162164
// Permissions
163165
await fastify.register(getAllPermissions);

src/server/routes/webhooks/test.ts

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { Type, type Static } from "@sinclair/typebox";
2+
import type { FastifyInstance } from "fastify";
3+
import { StatusCodes } from "http-status-codes";
4+
import { getWebhook } from "../../../db/webhooks/getWebhook";
5+
import { sendWebhookRequest } from "../../../utils/webhook";
6+
import { createCustomError } from "../../middleware/error";
7+
import { NumberStringSchema } from "../../schemas/number";
8+
import { standardResponseSchema } from "../../schemas/sharedApiSchemas";
9+
import type { TransactionSchema } from "../../schemas/transaction";
10+
11+
const paramsSchema = Type.Object({
12+
webhookId: NumberStringSchema,
13+
});
14+
15+
const responseBodySchema = Type.Object({
16+
result: Type.Object({
17+
ok: Type.Boolean(),
18+
status: Type.Number(),
19+
body: Type.String(),
20+
}),
21+
});
22+
23+
export async function testWebhookRoute(fastify: FastifyInstance) {
24+
fastify.route<{
25+
Params: Static<typeof paramsSchema>;
26+
Reply: Static<typeof responseBodySchema>;
27+
}>({
28+
method: "POST",
29+
url: "/webhooks/:webhookId/test",
30+
schema: {
31+
summary: "Test webhook",
32+
description: "Send a test payload to a webhook.",
33+
tags: ["Webhooks"],
34+
operationId: "testWebhook",
35+
params: paramsSchema,
36+
response: {
37+
...standardResponseSchema,
38+
[StatusCodes.OK]: responseBodySchema,
39+
},
40+
},
41+
handler: async (req, res) => {
42+
const { webhookId } = req.params;
43+
44+
const webhook = await getWebhook(Number.parseInt(webhookId));
45+
if (!webhook) {
46+
throw createCustomError(
47+
"Webhook not found.",
48+
StatusCodes.BAD_REQUEST,
49+
"NOT_FOUND",
50+
);
51+
}
52+
53+
const webhookBody: Static<typeof TransactionSchema> = {
54+
// Queue details
55+
queueId: "1411246e-b1c8-4f5d-9a25-8c1f40b54e55",
56+
status: "mined",
57+
onchainStatus: "success",
58+
queuedAt: "2023-09-29T22:01:31.031Z",
59+
sentAt: "2023-09-29T22:01:41.580Z",
60+
minedAt: "2023-09-29T22:01:44.000Z",
61+
errorMessage: null,
62+
cancelledAt: null,
63+
retryCount: 0,
64+
65+
// Onchain details
66+
chainId: "80002",
67+
fromAddress: "0x3ecdbf3b911d0e9052b64850693888b008e18373",
68+
toAddress: "0x365b83d67d5539c6583b9c0266a548926bf216f4",
69+
data: "0xa9059cbb0000000000000000000000003ecdbf3b911d0e9052b64850693888b008e183730000000000000000000000000000000000000000000000000000000000000064",
70+
value: "0x00",
71+
nonce: 1786,
72+
gasLimit: "39580",
73+
maxFeePerGas: "2063100466",
74+
maxPriorityFeePerGas: "1875545856",
75+
gasPrice: "1875545871",
76+
transactionType: 2,
77+
transactionHash:
78+
"0xc3ffa42dd4734b017d483e1158a2e936c8a97dd1aa4e4ce11df80ac8e81d2c7e",
79+
sentAtBlockNumber: 40660021,
80+
blockNumber: 40660026,
81+
82+
// User operation (account abstraction) details
83+
signerAddress: null,
84+
accountAddress: null,
85+
accountFactoryAddress: null,
86+
target: null,
87+
sender: null,
88+
initCode: null,
89+
callData: null,
90+
callGasLimit: null,
91+
verificationGasLimit: null,
92+
preVerificationGas: null,
93+
paymasterAndData: null,
94+
userOpHash: null,
95+
accountSalt: null,
96+
97+
// Off-chain details
98+
functionName: "transfer",
99+
functionArgs: "0x3ecdbf3b911d0e9052b64850693888b008e18373,100",
100+
extension: "none",
101+
deployedContractAddress: null,
102+
deployedContractType: null,
103+
104+
// Deprecated
105+
retryGasValues: null,
106+
retryMaxFeePerGas: null,
107+
retryMaxPriorityFeePerGas: null,
108+
effectiveGasPrice: null,
109+
cumulativeGasUsed: null,
110+
onChainTxStatus: 1,
111+
};
112+
113+
const resp = await sendWebhookRequest(webhook, webhookBody);
114+
115+
res.status(StatusCodes.OK).send({
116+
result: resp,
117+
});
118+
},
119+
});
120+
}

0 commit comments

Comments
 (0)