Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
181 changes: 115 additions & 66 deletions src/ogv/post-processors/governance.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,76 @@
import { EvmBatchProcessor } from '@subsquid/evm-processor'

import * as erc20Abi from '../../abi/erc20'
import * as governanceAbi from '../../abi/governance'
import { OGVAddress, OGVProposal, OGVProposalEvent, OGVProposalState, OGVProposalTxLog, OGVProposalVote, OGVVoteType } from '../../model'
import { Block, Context, Log } from '../../processor'
import {
GOVERNANCE_ADDRESS,
OGV_ADDRESS,
VEOGV_ADDRESS,
} from '../../utils/addresses'
OGVAddress,
OGVProposal,
OGVProposalEvent,
OGVProposalState,
OGVProposalTxLog,
OGVProposalVote,
OGVVoteType,
} from '../../model'
import { Block, Context, Log } from '../../processor'
import { GOVERNANCE_ADDRESS } from '../../utils/addresses'

export const from = 14439231 // https://etherscan.io/tx/0x9295cac246169f06a3d4ec33fdbd87fced7a9e19ea61177cae75034e45ae66f4
export const veogvFrom = 15089597 // https://etherscan.io/tx/0x70c582e56ea1c49b7e9df70a0b40ddbfac9362b8b172cb527c329c2302d7d48a
export const from = 15491391 // https://etherscan.io/tx/0x0e04e429248c384e6b36229edf8eb5a77bec7023c58808c21b702edfcbc0e0d6

interface IProcessResult {
addresses: Map<string, OGVAddress>,
proposals: Map<string, OGVProposal>,
proposalLogs: OGVProposalTxLog[],
votes: OGVProposalVote[],
addresses: Map<string, OGVAddress>
proposals: Map<string, OGVProposal>
proposalLogs: OGVProposalTxLog[]
votes: OGVProposalVote[]
}

export const setup = (processor: EvmBatchProcessor) => {
processor.addLog({
address: [OGV_ADDRESS],
topic0: [erc20Abi.events.Transfer.topic],
range: { from },
})
processor.addLog({
address: [VEOGV_ADDRESS],
address: [GOVERNANCE_ADDRESS],
topic0: [
governanceAbi.events.ProposalCreated,
governanceAbi.events.ProposalExecuted,
governanceAbi.events.ProposalExtended,
governanceAbi.events.ProposalQueued,
governanceAbi.events.ProposalCanceled,
governanceAbi.events.VoteCast,
governanceAbi.events.VoteCastWithParams,
].map(ev => ev.topic),
range: { from: veogvFrom },
governanceAbi.events.ProposalCreated.topic,
governanceAbi.events.ProposalExecuted.topic,
governanceAbi.events.ProposalExtended.topic,
governanceAbi.events.ProposalQueued.topic,
governanceAbi.events.ProposalCanceled.topic,
governanceAbi.events.VoteCast.topic,
governanceAbi.events.VoteCastWithParams.topic,
],
range: { from },
})
}

export const process = async (ctx: Context) => {
if (ctx.blocks[ctx.blocks.length - 1]?.header.height < from) return

const result: IProcessResult = {
addresses: new Map<string, OGVAddress>(),
proposals: new Map<string, OGVProposal>(),
proposalLogs: [],
votes: []
votes: [],
}

for (const block of ctx.blocks) {
for (const log of block.logs) {
const firstTopic = log.topics[0]

if (![VEOGV_ADDRESS, OGV_ADDRESS].includes(log.address)) {
return
}
if (log.address !== GOVERNANCE_ADDRESS) continue

const firstTopic = log.topics[0]
if (firstTopic == governanceAbi.events.ProposalCreated.topic) {
await _processProposalCreated(ctx, result, block, log);
await _processProposalCreated(ctx, result, block, log)
} else if (firstTopic == governanceAbi.events.ProposalExtended.topic) {
await _processProposalExtended(ctx, result, block, log);
} else if ([governanceAbi.events.ProposalQueued.topic, governanceAbi.events.ProposalCanceled.topic, governanceAbi.events.ProposalExecuted.topic].includes(firstTopic)) {
await _processProposalEvents(ctx, result, block, log);
} else if ([governanceAbi.events.VoteCast.topic, governanceAbi.events.VoteCastWithParams.topic].includes(firstTopic)) {
await _processProposalExtended(ctx, result, block, log)
} else if (
[
governanceAbi.events.ProposalQueued.topic,
governanceAbi.events.ProposalCanceled.topic,
governanceAbi.events.ProposalExecuted.topic,
].includes(firstTopic)
) {
await _processProposalEvents(ctx, result, block, log)
} else if (
[
governanceAbi.events.VoteCast.topic,
governanceAbi.events.VoteCastWithParams.topic,
].includes(firstTopic)
) {
await _processVoteCast(ctx, result, block, log)
}
}
Expand All @@ -79,9 +86,16 @@ const _processProposalCreated = async (
ctx: Context,
result: IProcessResult,
block: Block,
log: Log
log: Log,
) => {
const { proposalId, proposer: proposerAddr, description, startBlock, endBlock } = governanceAbi.events.ProposalCreated.decode(log)
// ctx.log.info('_processProposalCreated')
const {
proposalId,
proposer: proposerAddr,
description,
startBlock,
endBlock,
} = governanceAbi.events.ProposalCreated.decode(log)
const proposer = await _getAddress(ctx, proposerAddr, result)
const blockTimestamp = new Date(block.header.timestamp)

Expand All @@ -93,7 +107,7 @@ const _processProposalCreated = async (
startBlock,
endBlock,
lastUpdated: new Date(),
status: OGVProposalState.Pending
status: OGVProposalState.Pending,
})

const proposalTxLog = new OGVProposalTxLog({
Expand Down Expand Up @@ -121,36 +135,42 @@ const proposalStateMap = [

const eventMapper = {
[governanceAbi.events.ProposalQueued.topic]: {
decode: governanceAbi.events.ProposalQueued.decode,
decode: governanceAbi.events.ProposalQueued.decode.bind(
governanceAbi.events.ProposalQueued,
),
status: OGVProposalState.Queued,
event: OGVProposalEvent.Queued
event: OGVProposalEvent.Queued,
},
[governanceAbi.events.ProposalCanceled.topic]: {
decode: governanceAbi.events.ProposalCanceled.decode,
decode: governanceAbi.events.ProposalCanceled.decode.bind(
governanceAbi.events.ProposalCanceled,
),
status: OGVProposalState.Canceled,
event: OGVProposalEvent.Canceled
event: OGVProposalEvent.Canceled,
},
[governanceAbi.events.ProposalExecuted.topic]: {
decode: governanceAbi.events.ProposalExecuted.decode,
decode: governanceAbi.events.ProposalExecuted.decode.bind(
governanceAbi.events.ProposalExecuted,
),
status: OGVProposalState.Executed,
event: OGVProposalEvent.Executed
event: OGVProposalEvent.Executed,
},
}

const _processProposalEvents = async (
ctx: Context,
result: IProcessResult,
block: Block,
log: Log
log: Log,
) => {
// ctx.log.info('_processProposalEvents')
const { decode, status, event } = eventMapper[log.topics[0]]!

const { proposalId } = decode(log)
const blockTimestamp = new Date(block.header.timestamp)

const proposal = await _getProposal(ctx, proposalId.toString(), result)
proposal.status = status;

proposal.status = status

const proposalTxLog = new OGVProposalTxLog({
id: `${proposalId}:${log.transactionHash}:${log.logIndex}`,
Expand All @@ -167,9 +187,11 @@ const _processProposalExtended = async (
ctx: Context,
result: IProcessResult,
block: Block,
log: Log
log: Log,
) => {
const { proposalId, extendedDeadline } = governanceAbi.events.ProposalExtended.decode(log)
// ctx.log.info('_processProposalExtended')
const { proposalId, extendedDeadline } =
governanceAbi.events.ProposalExtended.decode(log)
const blockTimestamp = new Date(block.header.timestamp)

const proposal = await _getProposal(ctx, proposalId.toString(), result)
Expand All @@ -191,10 +213,17 @@ const _processVoteCast = async (
ctx: Context,
result: IProcessResult,
block: Block,
log: Log
log: Log,
) => {
const decode = (log.topics[0] == governanceAbi.events.VoteCast.topic) ? governanceAbi.events.VoteCast.decode : governanceAbi.events.VoteCastWithParams.decode
const { proposalId, voter: voterAddr, weight, support } = decode(log)
// ctx.log.info('_processVoteCast')
const {
proposalId,
voter: voterAddr,
weight,
support,
} = log.topics[0] == governanceAbi.events.VoteCast.topic
? governanceAbi.events.VoteCast.decode(log)
: governanceAbi.events.VoteCastWithParams.decode(log)
const blockTimestamp = new Date(block.header.timestamp)

const proposal = await _getProposal(ctx, proposalId.toString(), result)
Expand All @@ -207,20 +236,36 @@ const _processVoteCast = async (
txHash: log.transactionHash,
timestamp: blockTimestamp,
weight,
type: [OGVVoteType.Against, OGVVoteType.For, OGVVoteType.Abstain][parseInt(support.toString())]
type: [OGVVoteType.Against, OGVVoteType.For, OGVVoteType.Abstain][
parseInt(support.toString())
],
})

result.votes.push(proposalVote)
}

const _getProposalState = async (ctx: Context, block: Block, proposalId: bigint): Promise<OGVProposalState> => {
const governance = new governanceAbi.Contract(ctx, block.header, GOVERNANCE_ADDRESS)
return proposalStateMap[
parseInt((await governance.state(proposalId)).toString())
] || OGVProposalState.Pending;
const _getProposalState = async (
ctx: Context,
block: Block,
proposalId: bigint,
): Promise<OGVProposalState> => {
const governance = new governanceAbi.Contract(
ctx,
block.header,
GOVERNANCE_ADDRESS,
)
return (
proposalStateMap[
parseInt((await governance.state(proposalId)).toString())
] || OGVProposalState.Pending
)
}

const _getAddress = async (ctx: Context, id: string, result: IProcessResult): Promise<OGVAddress> => {
const _getAddress = async (
ctx: Context,
id: string,
result: IProcessResult,
): Promise<OGVAddress> => {
id = id.toLowerCase()
const { addresses } = result

Expand All @@ -229,23 +274,27 @@ const _getAddress = async (ctx: Context, id: string, result: IProcessResult): Pr
}

const address = await ctx.store.findOneByOrFail(OGVAddress, {
id
id,
})

addresses.set(id, address)

return address
}

const _getProposal = async (ctx: Context, id: string, result: IProcessResult): Promise<OGVProposal> => {
const _getProposal = async (
ctx: Context,
id: string,
result: IProcessResult,
): Promise<OGVProposal> => {
const { proposals } = result

if (proposals.has(id)) {
return proposals.get(id)!
}

const proposal = await ctx.store.findOneByOrFail(OGVProposal, {
id
id,
})

proposals.set(id, proposal)
Expand Down
20 changes: 11 additions & 9 deletions src/ogv/processors/ogv-supply.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { EvmBatchProcessor } from '@subsquid/evm-processor';
import { Context } from '../../processor';
import { blockFrequencyUpdater } from '../../utils/blockFrequencyUpdater';
import { OGV } from '../../model';
import { EvmBatchProcessor } from '@subsquid/evm-processor'

import * as erc20Abi from '../../abi/erc20'
import { OGV_ADDRESS, VEOGV_ADDRESS } from '../../utils/addresses';
import { OGV } from '../../model'
import { Context } from '../../processor'
import { OGV_ADDRESS, VEOGV_ADDRESS } from '../../utils/addresses'
import { blockFrequencyUpdater } from '../../utils/blockFrequencyUpdater'

export const from = 14439231 // https://etherscan.io/tx/0x9295cac246169f06a3d4ec33fdbd87fced7a9e19ea61177cae75034e45ae66f4

export const setup = (processor: EvmBatchProcessor) => {
processor.includeAllBlocks({
from
from,
})
}
const update = blockFrequencyUpdater({ from })

const update = blockFrequencyUpdater({ from })
export const process = async (ctx: Context) => {
const supplyData: OGV[] = []

await update(ctx, async (ctx, block) => {
const ogvToken = new erc20Abi.Contract(ctx, block.header, OGV_ADDRESS)

const staked = await ogvToken.balanceOf(VEOGV_ADDRESS)
const total = await ogvToken.totalSupply()
const [staked, total] = await Promise.all([
ogvToken.balanceOf(VEOGV_ADDRESS),
ogvToken.totalSupply(),
])
const circulating = total - staked

const supplyAtBlock = new OGV({
Expand Down
Loading