@@ -2,7 +2,7 @@ import { type Static, Type } from "@sinclair/typebox";
22import type { FastifyInstance } from "fastify" ;
33import { StatusCodes } from "http-status-codes" ;
44import { getContract } from "thirdweb" ;
5- import { isContractDeployed } from "thirdweb/utils" ;
5+ import { isContractDeployed , shortenAddress } from "thirdweb/utils" ;
66import { upsertChainIndexer } from "../../../../shared/db/chain-indexers/upsert-chain-indexer" ;
77import { createContractSubscription } from "../../../../shared/db/contract-subscriptions/create-contract-subscription" ;
88import { getContractSubscriptionsUniqueChainIds } from "../../../../shared/db/contract-subscriptions/get-contract-subscriptions" ;
@@ -21,16 +21,26 @@ import {
2121import { standardResponseSchema } from "../../../schemas/shared-api-schemas" ;
2222import { getChainIdFromChain } from "../../../utils/chain" ;
2323import { isValidWebhookUrl } from "../../../utils/validator" ;
24+ import { getWebhook } from "../../../../shared/db/webhooks/get-webhook" ;
25+ import type { Webhooks } from "@prisma/client" ;
2426
2527const bodySchema = Type . Object ( {
2628 chain : chainIdOrSlugSchema ,
2729 contractAddress : {
2830 ...AddressSchema ,
2931 description : "The address for the contract." ,
3032 } ,
33+ webhookId : Type . Optional (
34+ Type . Number ( {
35+ description :
36+ "The ID of an existing webhook to use for this contract subscription. Either `webhookId` or `webhookUrl` must be provided." ,
37+ examples : [ 1 ] ,
38+ } ) ,
39+ ) ,
3140 webhookUrl : Type . Optional (
3241 Type . String ( {
33- description : "Webhook URL" ,
42+ description :
43+ "Creates a new webhook to call when new onchain data is detected. Either `webhookId` or `webhookUrl` must be provided." ,
3444 examples : [ "https://example.com/webhook" ] ,
3545 } ) ,
3646 ) ,
@@ -91,6 +101,7 @@ export async function addContractSubscription(fastify: FastifyInstance) {
91101 const {
92102 chain,
93103 contractAddress,
104+ webhookId,
94105 webhookUrl,
95106 processEventLogs,
96107 filterEvents = [ ] ,
@@ -124,6 +135,25 @@ export async function addContractSubscription(fastify: FastifyInstance) {
124135 ) ;
125136 }
126137
138+ // Get an existing webhook or create a new one.
139+ let webhook : Webhooks | null = null ;
140+ if ( webhookId ) {
141+ webhook = await getWebhook ( webhookId ) ;
142+ } else if ( webhookUrl && isValidWebhookUrl ( webhookUrl ) ) {
143+ webhook = await insertWebhook ( {
144+ eventType : WebhooksEventTypes . CONTRACT_SUBSCRIPTION ,
145+ name : `(Generated) Subscription for ${ shortenAddress ( contractAddress ) } ` ,
146+ url : webhookUrl ,
147+ } ) ;
148+ }
149+ if ( ! webhook ) {
150+ throw createCustomError (
151+ 'Failed to get or create webhook for contract subscription. Make sure you provide an valid "webhookId" or "webhookUrl".' ,
152+ StatusCodes . BAD_REQUEST ,
153+ "INVALID_WEBHOOK" ,
154+ ) ;
155+ }
156+
127157 // If not currently indexed, upsert the latest block number.
128158 const subscribedChainIds = await getContractSubscriptionsUniqueChainIds ( ) ;
129159 if ( ! subscribedChainIds . includes ( chainId ) ) {
@@ -137,30 +167,11 @@ export async function addContractSubscription(fastify: FastifyInstance) {
137167 }
138168 }
139169
140- // Create the webhook (if provided).
141- let webhookId : number | undefined ;
142- if ( webhookUrl ) {
143- if ( ! isValidWebhookUrl ( webhookUrl ) ) {
144- throw createCustomError (
145- "Invalid webhook URL. Make sure it starts with 'https://'." ,
146- StatusCodes . BAD_REQUEST ,
147- "BAD_REQUEST" ,
148- ) ;
149- }
150-
151- const webhook = await insertWebhook ( {
152- eventType : WebhooksEventTypes . CONTRACT_SUBSCRIPTION ,
153- name : "(Auto-generated)" ,
154- url : webhookUrl ,
155- } ) ;
156- webhookId = webhook . id ;
157- }
158-
159170 // Create the contract subscription.
160171 const contractSubscription = await createContractSubscription ( {
161172 chainId,
162173 contractAddress : contractAddress . toLowerCase ( ) ,
163- webhookId,
174+ webhookId : webhook . id ,
164175 processEventLogs,
165176 filterEvents,
166177 processTransactionReceipts,
0 commit comments