Skip to content

chore: Create contract subscription for existing webhook #862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 6, 2025
Merged
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type Static, Type } from "@sinclair/typebox";
import type { FastifyInstance } from "fastify";
import { StatusCodes } from "http-status-codes";
import { getContract } from "thirdweb";
import { isContractDeployed } from "thirdweb/utils";
import { isContractDeployed, shortenAddress } from "thirdweb/utils";
import { upsertChainIndexer } from "../../../../shared/db/chain-indexers/upsert-chain-indexer";
import { createContractSubscription } from "../../../../shared/db/contract-subscriptions/create-contract-subscription";
import { getContractSubscriptionsUniqueChainIds } from "../../../../shared/db/contract-subscriptions/get-contract-subscriptions";
Expand All @@ -21,16 +21,26 @@ import {
import { standardResponseSchema } from "../../../schemas/shared-api-schemas";
import { getChainIdFromChain } from "../../../utils/chain";
import { isValidWebhookUrl } from "../../../utils/validator";
import { getWebhook } from "../../../../shared/db/webhooks/get-webhook";
import { Webhooks } from "@prisma/client";

const bodySchema = Type.Object({
chain: chainIdOrSlugSchema,
contractAddress: {
...AddressSchema,
description: "The address for the contract.",
},
webhookId: Type.Optional(
Type.Number({
description:
"The ID of an existing webhook to use for this contract subscription. Either `webhookId` or `webhookUrl` must be provided.",
examples: [1],
}),
),
webhookUrl: Type.Optional(
Type.String({
description: "Webhook URL",
description:
"Creates a new webhook to call when new onchain data is detected. Either `webhookId` or `webhookUrl` must be provided.",
examples: ["https://example.com/webhook"],
}),
),
Expand Down Expand Up @@ -91,6 +101,7 @@ export async function addContractSubscription(fastify: FastifyInstance) {
const {
chain,
contractAddress,
webhookId,
webhookUrl,
processEventLogs,
filterEvents = [],
Expand Down Expand Up @@ -124,6 +135,25 @@ export async function addContractSubscription(fastify: FastifyInstance) {
);
}

// Get an existing webhook or create a new one.
let webhook: Webhooks | null = null;
if (webhookId) {
webhook = await getWebhook(webhookId);
} else if (webhookUrl && isValidWebhookUrl(webhookUrl)) {
webhook = await insertWebhook({
eventType: WebhooksEventTypes.CONTRACT_SUBSCRIPTION,
name: `(Generated) Subscription for ${shortenAddress(contractAddress)}`,
url: webhookUrl,
});
}
if (!webhook) {
throw createCustomError(
'Failed to get or create webhook for contract subscription. Make sure you provide an valid "webhookId" or "webhookUrl".',
StatusCodes.BAD_REQUEST,
"INVALID_WEBHOOK",
);
}

// If not currently indexed, upsert the latest block number.
const subscribedChainIds = await getContractSubscriptionsUniqueChainIds();
if (!subscribedChainIds.includes(chainId)) {
Expand All @@ -137,30 +167,11 @@ export async function addContractSubscription(fastify: FastifyInstance) {
}
}

// Create the webhook (if provided).
let webhookId: number | undefined;
if (webhookUrl) {
if (!isValidWebhookUrl(webhookUrl)) {
throw createCustomError(
"Invalid webhook URL. Make sure it starts with 'https://'.",
StatusCodes.BAD_REQUEST,
"BAD_REQUEST",
);
}

const webhook = await insertWebhook({
eventType: WebhooksEventTypes.CONTRACT_SUBSCRIPTION,
name: "(Auto-generated)",
url: webhookUrl,
});
webhookId = webhook.id;
}

// Create the contract subscription.
const contractSubscription = await createContractSubscription({
chainId,
contractAddress: contractAddress.toLowerCase(),
webhookId,
webhookId: webhook.id,
processEventLogs,
filterEvents,
processTransactionReceipts,
Expand Down
Loading