Skip to content

Commit

Permalink
Added proposal execution and closure inbox notification webhooks.
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Sep 29, 2023
1 parent 163364c commit f5ea27e
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/data/webhooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { State } from '@/db'
import { makeProposalCreated } from './discordNotifier'
import { makeIndexerCwReceiptPaid } from './indexerCwReceipt'
import { makeInboxJoinedDao } from './notify/dao'
import { makeInboxProposalCreated } from './notify/proposal'
import {
makeInboxProposalClosed,
makeInboxProposalCreated,
makeInboxProposalExecuted,
} from './notify/proposal'
import { makeBroadcastVoteCast, makeProposalStatusChanged } from './websockets'

let processedWebhooks: ProcessedWebhook[] | undefined
Expand All @@ -18,6 +22,8 @@ export const getProcessedWebhooks = (
makeProposalCreated,
makeInboxJoinedDao,
makeInboxProposalCreated,
makeInboxProposalExecuted,
makeInboxProposalClosed,
makeIndexerCwReceiptPaid,
makeBroadcastVoteCast,
makeProposalStatusChanged,
Expand Down
142 changes: 142 additions & 0 deletions src/data/webhooks/notify/proposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,145 @@ export const makeInboxProposalCreated: WebhookMaker = (config, state) => ({
}
},
})

// Fire webhook when a proposal is executed.
export const makeInboxProposalExecuted: WebhookMaker = (config, state) => ({
filter: {
codeIdsKeys: CODE_IDS_KEYS,
matches: (event) =>
// Starts with proposals or proposals_v2.
(event.key.startsWith(KEY_PREFIX_PROPOSALS) ||
event.key.startsWith(KEY_PREFIX_PROPOSALS_V2)) &&
(event.valueJson.status === Status.Executed ||
event.valueJson.status === Status.ExecutionFailed),
},
endpoint: {
type: WebhookType.Url,
url: 'https://notifier.daodao.zone/notify',
method: 'POST',
headers: {
'x-api-key': config.notifierSecret,
},
},
getValue: async (event, getLastValue, env) => {
// Only fire the webhook if the last event was not executed.
const lastValue = await getLastValue()
if (
lastValue &&
(lastValue.status === Status.Executed ||
lastValue.status === Status.ExecutionFailed)
) {
return
}

// Get DAO config and proposal modules for this DAO so we can retrieve the
// DAO's name and the prefix for this proposal module.
const daoAddress = await getDaoAddressForProposalModule(env)
if (!daoAddress) {
return
}

const daoConfig = await daoCoreConfig.compute({
...env,
contractAddress: daoAddress,
})
const proposalModules = await activeProposalModules.compute({
...env,
contractAddress: daoAddress,
})
const proposalModule = proposalModules?.find(
(proposalModule) => proposalModule.address === event.contractAddress
)

if (!daoConfig || !proposalModule) {
return
}

// "proposals"|"proposals_v2", proposalNum
const [, proposalNum] = dbKeyToKeys(event.key, [false, true])
const proposalId = `${proposalModule.prefix}${proposalNum}`
const proposal: SingleChoiceProposal | MultipleChoiceProposal =
event.valueJson

return {
type: 'proposal_executed',
data: {
chainId: state.chainId,
dao: daoAddress,
daoName: daoConfig.name,
imageUrl: daoConfig.image_url ?? undefined,
proposalId,
proposalTitle: proposal.title,
failed: event.valueJson.status === Status.ExecutionFailed,
},
}
},
})

// Fire webhook when a proposal is closed.
export const makeInboxProposalClosed: WebhookMaker = (config, state) => ({
filter: {
codeIdsKeys: CODE_IDS_KEYS,
matches: (event) =>
// Starts with proposals or proposals_v2.
(event.key.startsWith(KEY_PREFIX_PROPOSALS) ||
event.key.startsWith(KEY_PREFIX_PROPOSALS_V2)) &&
event.valueJson.status === Status.Closed,
},
endpoint: {
type: WebhookType.Url,
url: 'https://notifier.daodao.zone/notify',
method: 'POST',
headers: {
'x-api-key': config.notifierSecret,
},
},
getValue: async (event, getLastValue, env) => {
// Only fire the webhook if the last event was not closed.
const lastValue = await getLastValue()
if (lastValue && lastValue.status === Status.Closed) {
return
}

// Get DAO config and proposal modules for this DAO so we can retrieve the
// DAO's name and the prefix for this proposal module.
const daoAddress = await getDaoAddressForProposalModule(env)
if (!daoAddress) {
return
}

const daoConfig = await daoCoreConfig.compute({
...env,
contractAddress: daoAddress,
})
const proposalModules = await activeProposalModules.compute({
...env,
contractAddress: daoAddress,
})
const proposalModule = proposalModules?.find(
(proposalModule) => proposalModule.address === event.contractAddress
)

if (!daoConfig || !proposalModule) {
return
}

// "proposals"|"proposals_v2", proposalNum
const [, proposalNum] = dbKeyToKeys(event.key, [false, true])
const proposalId = `${proposalModule.prefix}${proposalNum}`
const proposal: SingleChoiceProposal | MultipleChoiceProposal =
event.valueJson

return {
type: 'proposal_closed',
data: {
chainId: state.chainId,
dao: daoAddress,
daoName: daoConfig.name,
imageUrl: daoConfig.image_url ?? undefined,
proposalId,
proposalTitle: proposal.title,
},
}
},
})

0 comments on commit f5ea27e

Please sign in to comment.