Skip to content

Commit f4f1d04

Browse files
committed
Create createEventProcessor to offer a simpler way to do basic event processing.
- Add processing of `AccountingConsensusRewards` and `ExecutionRewardsCollected` events
1 parent c701495 commit f4f1d04

File tree

11 files changed

+296
-9
lines changed

11 files changed

+296
-9
lines changed

abi/fee-accumulator.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[
2+
{
3+
"inputs": [{ "internalType": "address", "name": "_strategy", "type": "address" }],
4+
"stateMutability": "nonpayable",
5+
"type": "constructor"
6+
},
7+
{
8+
"anonymous": false,
9+
"inputs": [
10+
{ "indexed": true, "internalType": "address", "name": "strategy", "type": "address" },
11+
{ "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" }
12+
],
13+
"name": "ExecutionRewardsCollected",
14+
"type": "event"
15+
},
16+
{
17+
"inputs": [],
18+
"name": "STRATEGY",
19+
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
20+
"stateMutability": "view",
21+
"type": "function"
22+
},
23+
{
24+
"inputs": [],
25+
"name": "collect",
26+
"outputs": [{ "internalType": "uint256", "name": "eth", "type": "uint256" }],
27+
"stateMutability": "nonpayable",
28+
"type": "function"
29+
},
30+
{ "stateMutability": "payable", "type": "receive" }
31+
]

db/migrations/1729880820715-Data.js renamed to db/migrations/1729897704620-Data.js

Lines changed: 24 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

schema.graphql

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,7 +1384,7 @@ type LegacyStaker @entity {
13841384
rewardAmount: BigInt!
13851385
}
13861386

1387-
type BeaconDepositEvent @entity {
1387+
type BeaconDepositEvent @entity {
13881388
id: ID! # `chainId:logId`
13891389
chainId: Int! @index
13901390
address: String! @index
@@ -1400,13 +1400,33 @@ type BeaconDepositEvent @entity {
14001400
index: String!
14011401
}
14021402

1403-
type BeaconDepositPubkey @entity {
1403+
type BeaconDepositPubkey @entity {
14041404
id: ID! # `pubkey`
14051405
createDate: DateTime!
14061406
lastUpdated: DateTime!
14071407
count: Int!
14081408
deposits: [BeaconDepositEvent!] @derivedFrom(field: "pubkey")
1409-
}# OETH Vault: 0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab
1409+
}
1410+
1411+
type AccountingConsensusRewards @entity {
1412+
id: ID! # `chainId:logId`
1413+
chainId: Int! @index
1414+
timestamp: DateTime! @index
1415+
blockNumber: Int! @index
1416+
address: String! @index
1417+
rewards: BigInt!
1418+
}
1419+
1420+
type ExecutionRewardsCollected @entity {
1421+
id: ID! # `chainId:logId`
1422+
chainId: Int! @index
1423+
timestamp: DateTime! @index
1424+
blockNumber: Int! @index
1425+
address: String! @index
1426+
strategy: String! @index
1427+
amount: BigInt!
1428+
}
1429+
# OETH Vault: 0x39254033945AA2E4809Cc2977E7087BEE48bd7Ab
14101430
"""
14111431
The Vault entity tracks the OETH vault balance over time.
14121432
"""

schema/native-staking.graphql

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
type BeaconDepositEvent @entity {
1+
type BeaconDepositEvent @entity {
22
id: ID! # `chainId:logId`
33
chainId: Int! @index
44
address: String! @index
@@ -14,10 +14,29 @@ type BeaconDepositEvent @entity {
1414
index: String!
1515
}
1616

17-
type BeaconDepositPubkey @entity {
17+
type BeaconDepositPubkey @entity {
1818
id: ID! # `pubkey`
1919
createDate: DateTime!
2020
lastUpdated: DateTime!
2121
count: Int!
2222
deposits: [BeaconDepositEvent!] @derivedFrom(field: "pubkey")
23-
}
23+
}
24+
25+
type AccountingConsensusRewards @entity {
26+
id: ID! # `chainId:logId`
27+
chainId: Int! @index
28+
timestamp: DateTime! @index
29+
blockNumber: Int! @index
30+
address: String! @index
31+
rewards: BigInt!
32+
}
33+
34+
type ExecutionRewardsCollected @entity {
35+
id: ID! # `chainId:logId`
36+
chainId: Int! @index
37+
timestamp: DateTime! @index
38+
blockNumber: Int! @index
39+
address: String! @index
40+
strategy: String! @index
41+
amount: BigInt!
42+
}

src/abi/fee-accumulator.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as p from '@subsquid/evm-codec'
2+
import { event, fun, viewFun, indexed, ContractBase } from '@subsquid/evm-abi'
3+
import type { EventParams as EParams, FunctionArguments, FunctionReturn } from '@subsquid/evm-abi'
4+
5+
export const events = {
6+
ExecutionRewardsCollected: event("0xc2acb502a0dc166a61cd83b914b480d76050e91a6797d7a833be84c4eace1dfe", "ExecutionRewardsCollected(address,uint256)", {"strategy": indexed(p.address), "amount": p.uint256}),
7+
}
8+
9+
export const functions = {
10+
STRATEGY: viewFun("0x185025ef", "STRATEGY()", {}, p.address),
11+
collect: fun("0xe5225381", "collect()", {}, p.uint256),
12+
}
13+
14+
export class Contract extends ContractBase {
15+
16+
STRATEGY() {
17+
return this.eth_call(functions.STRATEGY, {})
18+
}
19+
}
20+
21+
/// Event types
22+
export type ExecutionRewardsCollectedEventArgs = EParams<typeof events.ExecutionRewardsCollected>
23+
24+
/// Function types
25+
export type STRATEGYParams = FunctionArguments<typeof functions.STRATEGY>
26+
export type STRATEGYReturn = FunctionReturn<typeof functions.STRATEGY>
27+
28+
export type CollectParams = FunctionArguments<typeof functions.collect>
29+
export type CollectReturn = FunctionReturn<typeof functions.collect>
30+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, IntColumn as IntColumn_, Index as Index_, DateTimeColumn as DateTimeColumn_, StringColumn as StringColumn_, BigIntColumn as BigIntColumn_} from "@subsquid/typeorm-store"
2+
3+
@Entity_()
4+
export class AccountingConsensusRewards {
5+
constructor(props?: Partial<AccountingConsensusRewards>) {
6+
Object.assign(this, props)
7+
}
8+
9+
@PrimaryColumn_()
10+
id!: string
11+
12+
@Index_()
13+
@IntColumn_({nullable: false})
14+
chainId!: number
15+
16+
@Index_()
17+
@DateTimeColumn_({nullable: false})
18+
timestamp!: Date
19+
20+
@Index_()
21+
@IntColumn_({nullable: false})
22+
blockNumber!: number
23+
24+
@Index_()
25+
@StringColumn_({nullable: false})
26+
address!: string
27+
28+
@BigIntColumn_({nullable: false})
29+
rewards!: bigint
30+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, IntColumn as IntColumn_, Index as Index_, DateTimeColumn as DateTimeColumn_, StringColumn as StringColumn_, BigIntColumn as BigIntColumn_} from "@subsquid/typeorm-store"
2+
3+
@Entity_()
4+
export class ExecutionRewardsCollected {
5+
constructor(props?: Partial<ExecutionRewardsCollected>) {
6+
Object.assign(this, props)
7+
}
8+
9+
@PrimaryColumn_()
10+
id!: string
11+
12+
@Index_()
13+
@IntColumn_({nullable: false})
14+
chainId!: number
15+
16+
@Index_()
17+
@DateTimeColumn_({nullable: false})
18+
timestamp!: Date
19+
20+
@Index_()
21+
@IntColumn_({nullable: false})
22+
blockNumber!: number
23+
24+
@Index_()
25+
@StringColumn_({nullable: false})
26+
address!: string
27+
28+
@Index_()
29+
@StringColumn_({nullable: false})
30+
strategy!: string
31+
32+
@BigIntColumn_({nullable: false})
33+
amount!: bigint
34+
}

src/model/generated/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ export * from "./_governanceVoteType"
108108
export * from "./legacyStaker.model"
109109
export * from "./beaconDepositEvent.model"
110110
export * from "./beaconDepositPubkey.model"
111+
export * from "./accountingConsensusRewards.model"
112+
export * from "./executionRewardsCollected.model"
111113
export * from "./oethVault.model"
112114
export * from "./oethCurveLp.model"
113115
export * from "./oethFraxStaking.model"

src/oeth/processors/strategies.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import * as feeAccumulatorAbi from '@abi/fee-accumulator'
2+
import * as nativeStakingAbi from '@abi/strategy-native-staking'
3+
import { AccountingConsensusRewards, ExecutionRewardsCollected } from '@model'
14
import { Context } from '@processor'
25
import { mainnetCurrencies } from '@shared/post-processors/exchange-rates/mainnetCurrencies'
36
import { EvmBatchProcessor } from '@subsquid/evm-processor'
7+
import { createEventProcessor } from '@templates/events/createEventProcessor'
48
import { IStrategyData, createStrategyProcessor, createStrategySetup } from '@templates/strategy'
59
import { createStrategyRewardProcessor, createStrategyRewardSetup } from '@templates/strategy-rewards'
610
import {
@@ -163,11 +167,50 @@ export const oethStrategies: readonly IStrategyData[] = [
163167

164168
const strategies = oethStrategies
165169

170+
const eventProcessors = [
171+
...OETH_NATIVE_STRATEGY_ADDRESSES.map((address) =>
172+
createEventProcessor({
173+
address,
174+
eventName: 'AccountingConsensusRewards',
175+
event: nativeStakingAbi.events.AccountingConsensusRewards,
176+
from: 20046251,
177+
Entity: AccountingConsensusRewards,
178+
mapEntity: (ctx, block, log, decoded) =>
179+
new AccountingConsensusRewards({
180+
id: `${ctx.chain.id}:${log.id}`,
181+
chainId: ctx.chain.id,
182+
timestamp: new Date(block.header.timestamp),
183+
blockNumber: block.header.height,
184+
address,
185+
rewards: decoded.amount,
186+
}),
187+
}),
188+
),
189+
createEventProcessor({
190+
address: addresses.oeth.nativeStakingFeeAccumulator,
191+
eventName: 'ExecutionRewardsCollected',
192+
event: feeAccumulatorAbi.events.ExecutionRewardsCollected,
193+
from: 20046238,
194+
Entity: ExecutionRewardsCollected,
195+
mapEntity: (ctx, block, log, decoded) =>
196+
new ExecutionRewardsCollected({
197+
id: `${ctx.chain.id}:${log.id}`,
198+
chainId: ctx.chain.id,
199+
timestamp: new Date(block.header.timestamp),
200+
blockNumber: block.header.height,
201+
address: addresses.oeth.nativeStakingFeeAccumulator,
202+
strategy: decoded.strategy,
203+
amount: decoded.amount,
204+
}),
205+
}),
206+
]
207+
166208
export const from = Math.min(...strategies.map((s) => s.from))
167209

168210
export const setup = (processor: EvmBatchProcessor) => {
169211
strategies.forEach((s) => createStrategySetup(s)(processor))
170212
strategies.filter((s) => s.kind !== 'Vault').forEach((s) => createStrategyRewardSetup(s)(processor))
213+
eventProcessors.forEach((p) => p.setup(processor))
171214
}
172215

173216
const processors = [
@@ -176,5 +219,5 @@ const processors = [
176219
]
177220

178221
export const process = async (ctx: Context) => {
179-
await Promise.all(processors.map((p) => p(ctx)))
222+
await Promise.all([...processors.map((p) => p(ctx)), ...eventProcessors.map((p) => p.process(ctx))])
180223
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Block, Context, Log } from '@processor'
2+
import { event } from '@subsquid/evm-abi'
3+
import { IndexedCodecs } from '@subsquid/evm-abi/lib/abi-components/event'
4+
import { DecodedStruct, Struct } from '@subsquid/evm-codec'
5+
import { EvmBatchProcessor } from '@subsquid/evm-processor'
6+
import { Entity } from '@subsquid/typeorm-store/lib/store'
7+
import { logFilter } from '@utils/logFilter'
8+
import { EntityClassT } from '@utils/type'
9+
10+
export const createEventProcessor = <T extends Struct, EventEntity extends Entity>(params: {
11+
eventName: string
12+
event: ReturnType<typeof event<T>>
13+
address: string
14+
from: number
15+
Entity: EntityClassT<EventEntity>
16+
mapEntity: (ctx: Context, block: Block, log: Log, decoded: DecodedStruct<IndexedCodecs<T>>) => EventEntity
17+
extraFilterArgs?: {
18+
topic1?: string[]
19+
topic2?: string[]
20+
topic3?: string[]
21+
}
22+
}) => {
23+
const filter = logFilter({
24+
address: [params.address],
25+
range: { from: params.from },
26+
topic0: [params.event.topic],
27+
...params.extraFilterArgs,
28+
})
29+
const setup = (p: EvmBatchProcessor) => {
30+
p.addLog(filter.value)
31+
}
32+
const process = async (ctx: Context) => {
33+
const entities: EventEntity[] = []
34+
for (const block of ctx.blocks) {
35+
for (const log of block.logs) {
36+
if (filter.matches(log)) {
37+
const decoded = params.event.decode(log)
38+
const entity = new params.Entity(params.mapEntity(ctx, block, log, decoded))
39+
entities.push(entity)
40+
}
41+
}
42+
}
43+
await ctx.store.insert(entities)
44+
}
45+
46+
return { from: params.from, setup, process }
47+
}

0 commit comments

Comments
 (0)