Skip to content

Commit

Permalink
feat: New project events (#1874)
Browse files Browse the repository at this point in the history
* new events migration

* proposal finish event

* added project enacted event
  • Loading branch information
ncomerci authored Jul 4, 2024
1 parent 889d613 commit 05a963c
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/entities/Proposal/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ErrorService } from '../../services/ErrorService'
import { ProjectService } from '../../services/ProjectService'
import { ProposalService } from '../../services/ProposalService'
import { DiscordService } from '../../services/discord'
import { EventsService } from '../../services/events'
import { NotificationService } from '../../services/notification'
import { ErrorCategory } from '../../utils/errorCategories'
import { isProdEnv } from '../../utils/governanceEnvs'
Expand Down Expand Up @@ -209,6 +210,7 @@ export async function finishProposal() {
BadgesService.giveFinishProposalBadges(proposalsWithOutcome)
DiscourseService.commentFinishedProposals(proposalsWithOutcome)
DiscordService.notifyFinishedProposals(proposalsWithOutcome)
await EventsService.proposalFinished(proposalsWithOutcome)
} catch (error) {
ErrorService.report('Error finishing proposals', { error, category: ErrorCategory.Job })
}
Expand Down
11 changes: 11 additions & 0 deletions src/migrations/1719945719397_add-new-event-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { MigrationBuilder } from "node-pg-migrate"
import { EventType } from "../shared/types/events"

export async function up(pgm: MigrationBuilder): Promise<void> {
pgm.addTypeValue({name: 'event_type'}, EventType.ProposalFinished)
pgm.addTypeValue({name: 'event_type'}, EventType.VestingCreated)
}

export async function down(): Promise<void> {
return
}
1 change: 1 addition & 0 deletions src/services/ProposalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export class ProposalService {
const project = await ProjectService.getUpdatedProject(proposal.project_id!)
updatedProposal.project_status = project.status
NotificationService.projectProposalEnacted(proposal)
await EventsService.projectEnacted(project)
}

DiscourseService.commentUpdatedProposal(updatedProposal)
Expand Down
42 changes: 42 additions & 0 deletions src/services/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ethers } from 'ethers'
import isEthereumAddress from 'validator/lib/isEthereumAddress'

import ProposalModel from '../entities/Proposal/model'
import { ProposalWithOutcome } from '../entities/Proposal/outcome'
import { ProposalAttributes } from '../entities/Proposal/types'
import { SNAPSHOT_SPACE } from '../entities/Snapshot/constants'
import UpdateModel from '../entities/Updates/model'
Expand All @@ -12,6 +13,7 @@ import { UserAttributes } from '../entities/User/types'
import { DISCOURSE_USER } from '../entities/User/utils'
import { addressShortener } from '../helpers'
import EventModel from '../models/Event'
import type { Project } from '../models/Project'
import CacheService, { TTL_1_HS } from '../services/CacheService'
import { DiscourseService } from '../services/DiscourseService'
import { ErrorService } from '../services/ErrorService'
Expand All @@ -27,11 +29,14 @@ import {
ProjectUpdateCommentedEvent,
ProposalCommentedEvent,
ProposalCreatedEvent,
ProposalFinishedEvent,
UpdateCreatedEvent,
VestingCreatedEvent,
VotedEvent,
} from '../shared/types/events'
import { DEFAULT_AVATAR_IMAGE, getProfiles } from '../utils/Catalyst'
import { DclProfile } from '../utils/Catalyst/types'
import Time from '../utils/date/Time'
import { ErrorCategory } from '../utils/errorCategories'

import { NotificationService } from './notification'
Expand Down Expand Up @@ -354,6 +359,43 @@ export class EventsService {
}
}

static async proposalFinished(proposalsWithOutcome: ProposalWithOutcome[]) {
for (const proposal of proposalsWithOutcome) {
const { id, title, newStatus, finish_at, user } = proposal
const finishEvent: ProposalFinishedEvent = {
id: crypto.randomUUID(),
address: user,
event_type: EventType.ProposalFinished,
event_data: { proposal_id: id, proposal_title: title, new_status: newStatus },
created_at: new Date(finish_at),
}
await EventModel.create(finishEvent)
}
}

static async projectEnacted(project: Project) {
const { author, id, proposal_id, funding } = project
if (!funding || !funding.vesting) {
ErrorService.report('Project enacted without vesting', { project_id: id, category: ErrorCategory.Events })
return
}
const { years, months, days } = Time(funding.vesting.finish_at).preciseDiff(Time(funding.vesting.start_at), true)
const vestingEvent: VestingCreatedEvent = {
id: crypto.randomUUID(),
address: author,
event_type: EventType.VestingCreated,
event_data: {
proposal_id,
proposal_title: project.title,
vesting_address: funding.vesting.address,
amount: funding.vesting.total,
duration_in_months: years * 12 + months + (days > 0 ? 1 : 0),
},
created_at: funding.enacted_at ? new Date(funding.enacted_at) : new Date(),
}
await EventModel.create(vestingEvent)
}

private static decodeLogTopics(topics: string[]) {
const methodSignature = topics[0]
const delegator = this.decodeTopicToAddress(topics[1])
Expand Down
24 changes: 24 additions & 0 deletions src/shared/types/events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { z } from 'zod'

import { ProposalStatus } from '../../entities/Proposal/types'

import { DiscourseWebhookPost } from './discourse'

export type CommonEventAttributes = {
Expand All @@ -26,6 +28,16 @@ export type DiscourseEventData = {
export type ProposalCommentedEventData = DiscourseEventData & ProposalEventData
export type UpdateCommentedEventData = DiscourseEventData & UpdateEventData & ProposalEventData

export type ProposalFinishedEventData = ProposalEventData & {
new_status: ProposalStatus
}

export type VestingCreatedEventData = ProposalEventData & {
vesting_address: string
amount: number
duration_in_months: number
}

type DelegationSetData = {
new_delegate: string | null
transaction_hash: string
Expand All @@ -39,11 +51,13 @@ type DelegationClearData = {
export enum EventType {
Voted = 'voted',
ProposalCreated = 'proposal_created',
ProposalFinished = 'proposal_finished',
UpdateCreated = 'update_created',
ProposalCommented = 'proposal_commented',
ProjectUpdateCommented = 'project_update_commented',
DelegationSet = 'delegation_set',
DelegationClear = 'delegation_clear',
VestingCreated = 'vesting_created',
}

export const EventFilterSchema = z.object({
Expand All @@ -64,6 +78,16 @@ export type ProposalCreatedEvent = {
event_data: ProposalEventData
} & CommonEventAttributes

export type ProposalFinishedEvent = {
event_type: EventType.ProposalFinished
event_data: ProposalFinishedEventData
} & CommonEventAttributes

export type VestingCreatedEvent = {
event_type: EventType.VestingCreated
event_data: VestingCreatedEventData
} & CommonEventAttributes

export type UpdateCreatedEvent = {
event_type: EventType.UpdateCreated
event_data: UpdateCreatedEventData
Expand Down

0 comments on commit 05a963c

Please sign in to comment.