Skip to content

Commit b15d665

Browse files
authored
Merge pull request #9 from edgeandnode/tmigone/data-service
feat: add data service entity
2 parents 57768b2 + 20c7353 commit b15d665

16 files changed

Lines changed: 907 additions & 52 deletions

packages/subgraph/schema.graphql

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ type GraphNetwork @entity(immutable: false) {
55
# Counts
66
"Active service providers"
77
countServiceProviders: Int!
8+
"Active data services (verifiers)"
9+
countDataServices: Int!
810
"Active provisions"
911
countProvisions: Int!
1012
"Active delegation pools"
@@ -90,15 +92,66 @@ type ServiceProvider @entity(immutable: false) {
9092
updatedAt: BigInt!
9193
}
9294

95+
type DataService @entity(immutable: false) {
96+
"Data service (verifier) contract address"
97+
id: Bytes!
98+
99+
# Relationships
100+
"Provisions for this data service"
101+
provisions: [Provision!]! @derivedFrom(field: "dataService")
102+
"Delegation pools for this data service"
103+
delegationPools: [DelegationPool!]! @derivedFrom(field: "dataService")
104+
105+
# Counts
106+
"Active service providers with provisions to this data service"
107+
countServiceProviders: Int!
108+
"Active provisions"
109+
countProvisions: Int!
110+
"Active delegation pools"
111+
countDelegationPools: Int!
112+
"Provision slash events"
113+
countProvisionSlashEvents: Int!
114+
"Delegation pool slash events"
115+
countDelegationPoolSlashEvents: Int!
116+
117+
# Tokens
118+
"Total tokens provisioned to this data service"
119+
tokensProvisioned: BigInt!
120+
"Total tokens delegated to service providers for this data service"
121+
tokensDelegated: BigInt!
122+
"Tokens currently thawing from provisions"
123+
tokensThawingFromProvisions: BigInt!
124+
"Tokens currently thawing from delegation pools"
125+
tokensThawingFromDelegationPools: BigInt!
126+
127+
# Slashing
128+
"Total tokens slashed"
129+
tokensSlashed: BigInt!
130+
"Tokens slashed from provisions"
131+
tokensSlashedFromProvisions: BigInt!
132+
"Tokens slashed from delegation pools"
133+
tokensSlashedFromDelegationPools: BigInt!
134+
135+
# Metadata
136+
"Block number when entity was created"
137+
createdAtBlock: BigInt!
138+
"Timestamp when entity was created"
139+
createdAt: BigInt!
140+
"Block number when entity was last updated"
141+
updatedAtBlock: BigInt!
142+
"Timestamp when entity was last updated"
143+
updatedAt: BigInt!
144+
}
145+
93146
type DelegationPool @entity(immutable: false) {
94-
"Composite ID: serviceProvider-verifier"
147+
"Composite ID: serviceProvider-dataService"
95148
id: Bytes!
96149

97150
# Relationships
98151
"Service provider that owns this pool"
99152
serviceProvider: ServiceProvider!
100-
"Verifier address (data service)"
101-
verifier: Bytes!
153+
"Data service (verifier)"
154+
dataService: DataService!
102155

103156
# Pool state
104157
"Total tokens in the pool"
@@ -124,14 +177,14 @@ type DelegationPool @entity(immutable: false) {
124177
}
125178

126179
type Provision @entity(immutable: false) {
127-
"Composite ID: serviceProvider-verifier"
180+
"Composite ID: serviceProvider-dataService"
128181
id: Bytes!
129182

130183
# Relationships
131184
"Service provider that created this provision"
132185
serviceProvider: ServiceProvider!
133-
"Verifier address (data service)"
134-
verifier: Bytes!
186+
"Data service (verifier)"
187+
dataService: DataService!
135188

136189
# Tokens
137190
"Tokens currently provisioned"
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"
2+
import { DataService } from "../../generated/schema"
3+
import { BIGINT_ZERO } from "../common/constants"
4+
5+
export class DataServiceResult {
6+
entity: DataService
7+
isNew: boolean
8+
9+
constructor(entity: DataService, isNew: boolean) {
10+
this.entity = entity
11+
this.isNew = isNew
12+
}
13+
}
14+
15+
export function getOrCreateDataService(
16+
id: Bytes,
17+
blockNumber: BigInt,
18+
timestamp: BigInt
19+
): DataServiceResult {
20+
let entity = DataService.load(id)
21+
let isNew = entity == null
22+
23+
if (entity == null) {
24+
entity = new DataService(id)
25+
26+
// Counts
27+
entity.countServiceProviders = 0
28+
entity.countProvisions = 0
29+
entity.countDelegationPools = 0
30+
entity.countProvisionSlashEvents = 0
31+
entity.countDelegationPoolSlashEvents = 0
32+
33+
// Tokens
34+
entity.tokensProvisioned = BIGINT_ZERO
35+
entity.tokensDelegated = BIGINT_ZERO
36+
entity.tokensThawingFromProvisions = BIGINT_ZERO
37+
entity.tokensThawingFromDelegationPools = BIGINT_ZERO
38+
39+
// Slashing
40+
entity.tokensSlashed = BIGINT_ZERO
41+
entity.tokensSlashedFromProvisions = BIGINT_ZERO
42+
entity.tokensSlashedFromDelegationPools = BIGINT_ZERO
43+
44+
// Metadata
45+
entity.createdAtBlock = blockNumber
46+
entity.createdAt = timestamp
47+
entity.updatedAtBlock = blockNumber
48+
entity.updatedAt = timestamp
49+
}
50+
51+
return new DataServiceResult(entity, isNew)
52+
}
53+
54+
export function saveDataService(ds: DataService, block: ethereum.Block): void {
55+
ds.updatedAtBlock = block.number
56+
ds.updatedAt = block.timestamp
57+
ds.save()
58+
}

packages/subgraph/src/entities/delegationPool.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"
22
import { DelegationPool } from "../../generated/schema"
33
import { BIGINT_ZERO } from "../common/constants"
44

5-
export function getDelegationPoolId(serviceProvider: Bytes, verifier: Bytes): Bytes {
6-
return serviceProvider.concat(verifier)
5+
export function getDelegationPoolId(serviceProvider: Bytes, dataService: Bytes): Bytes {
6+
return serviceProvider.concat(dataService)
77
}
88

99
export class DelegationPoolResult {
@@ -23,18 +23,18 @@ export class DelegationPoolResult {
2323
*/
2424
export function getOrCreateDelegationPool(
2525
serviceProvider: Bytes,
26-
verifier: Bytes,
26+
dataService: Bytes,
2727
blockNumber: BigInt,
2828
timestamp: BigInt
2929
): DelegationPoolResult {
30-
let id = getDelegationPoolId(serviceProvider, verifier)
30+
let id = getDelegationPoolId(serviceProvider, dataService)
3131
let entity = DelegationPool.load(id)
3232
let isNew = entity == null
3333

3434
if (entity == null) {
3535
entity = new DelegationPool(id)
3636
entity.serviceProvider = serviceProvider
37-
entity.verifier = verifier
37+
entity.dataService = dataService
3838
entity.tokens = BIGINT_ZERO
3939
entity.shares = BIGINT_ZERO
4040
entity.tokensThawing = BIGINT_ZERO

packages/subgraph/src/entities/graphNetwork.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export function getOrCreateGraphNetwork(): GraphNetwork {
88

99
// Counts
1010
entity.countServiceProviders = 0
11+
entity.countDataServices = 0
1112
entity.countProvisions = 0
1213
entity.countDelegationPools = 0
1314
entity.countProvisionSlashEvents = 0

packages/subgraph/src/entities/provision.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"
22
import { Provision } from "../../generated/schema"
33
import { BIGINT_ZERO } from "../common/constants"
44

5-
export function getProvisionId(serviceProvider: Bytes, verifier: Bytes): Bytes {
6-
return serviceProvider.concat(verifier)
5+
export function getProvisionId(serviceProvider: Bytes, dataService: Bytes): Bytes {
6+
return serviceProvider.concat(dataService)
77
}
88

99
export class ProvisionResult {
@@ -18,18 +18,18 @@ export class ProvisionResult {
1818

1919
export function getOrCreateProvision(
2020
serviceProvider: Bytes,
21-
verifier: Bytes,
21+
dataService: Bytes,
2222
blockNumber: BigInt,
2323
timestamp: BigInt
2424
): ProvisionResult {
25-
let id = getProvisionId(serviceProvider, verifier)
25+
let id = getProvisionId(serviceProvider, dataService)
2626
let entity = Provision.load(id)
2727
let isNew = entity == null
2828

2929
if (entity == null) {
3030
entity = new Provision(id)
3131
entity.serviceProvider = serviceProvider
32-
entity.verifier = verifier
32+
entity.dataService = dataService
3333
entity.tokens = BIGINT_ZERO
3434
entity.tokensThawing = BIGINT_ZERO
3535
entity.maxVerifierCut = BIGINT_ZERO

packages/subgraph/src/handlers/delegation.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from "../../generated/HorizonStaking/HorizonStaking"
99
import { getOrCreateGraphNetwork, saveGraphNetwork } from "../entities/graphNetwork"
1010
import { getOrCreateServiceProvider, saveServiceProvider } from "../entities/serviceProvider"
11+
import { getOrCreateDataService, saveDataService } from "../entities/dataService"
1112
import { getOrCreateDelegationPool, saveDelegationPool } from "../entities/delegationPool"
1213
import { BIGINT_ZERO } from "../common/constants"
1314

@@ -35,6 +36,15 @@ export function handleTokensDelegated(event: TokensDelegated): void {
3536
pool.entity.shares = pool.entity.shares.plus(shares)
3637
saveDelegationPool(pool.entity, event.block)
3738

39+
// Update DataService
40+
let dataService = getOrCreateDataService(verifierBytes, event.block.number, event.block.timestamp)
41+
assert(!dataService.isNew, "Data service does not exist.")
42+
dataService.entity.tokensDelegated = dataService.entity.tokensDelegated.plus(tokens)
43+
if (pool.isNew) {
44+
dataService.entity.countDelegationPools += 1
45+
}
46+
saveDataService(dataService.entity, event.block)
47+
3848
// Update ServiceProvider
3949
let serviceProvider = getOrCreateServiceProvider(serviceProviderBytes, event.block.number, event.block.timestamp)
4050
assert(!serviceProvider.isNew, "Service provider does not exist.")
@@ -76,6 +86,12 @@ export function handleTokensUndelegated(event: TokensUndelegated): void {
7686
pool.entity.tokensThawing = pool.entity.tokensThawing.plus(tokens)
7787
saveDelegationPool(pool.entity, event.block)
7888

89+
// Update DataService
90+
let dataService = getOrCreateDataService(verifierBytes, event.block.number, event.block.timestamp)
91+
assert(!dataService.isNew, "Data service does not exist.")
92+
dataService.entity.tokensThawingFromDelegationPools = dataService.entity.tokensThawingFromDelegationPools.plus(tokens)
93+
saveDataService(dataService.entity, event.block)
94+
7995
// Update ServiceProvider
8096
let serviceProvider = getOrCreateServiceProvider(serviceProviderBytes, event.block.number, event.block.timestamp)
8197
assert(!serviceProvider.isNew, "Service provider does not exist.")
@@ -114,6 +130,19 @@ export function handleDelegatedTokensWithdrawn(event: DelegatedTokensWithdrawn):
114130
pool.entity.tokensThawing = pool.entity.tokensThawing.minus(tokens)
115131
saveDelegationPool(pool.entity, event.block)
116132

133+
// Update DataService
134+
let dataService = getOrCreateDataService(verifierBytes, event.block.number, event.block.timestamp)
135+
assert(!dataService.isNew, "Data service does not exist.")
136+
assert(dataService.entity.tokensThawingFromDelegationPools >= tokens, "Withdraw tokens exceed data service tokens thawing.")
137+
dataService.entity.tokensThawingFromDelegationPools = dataService.entity.tokensThawingFromDelegationPools.minus(tokens)
138+
assert(dataService.entity.tokensDelegated >= tokens, "Withdraw tokens exceed data service tokens delegated.")
139+
dataService.entity.tokensDelegated = dataService.entity.tokensDelegated.minus(tokens)
140+
if (pool.entity.tokens.equals(BIGINT_ZERO)) {
141+
assert(dataService.entity.countDelegationPools > 0, "Data service delegation pool count is zero.")
142+
dataService.entity.countDelegationPools -= 1
143+
}
144+
saveDataService(dataService.entity, event.block)
145+
117146
// Update ServiceProvider
118147
let serviceProvider = getOrCreateServiceProvider(serviceProviderBytes, event.block.number, event.block.timestamp)
119148
assert(!serviceProvider.isNew, "Service provider does not exist.")
@@ -160,6 +189,16 @@ export function handleDelegationSlashed(event: DelegationSlashed): void {
160189
pool.entity.tokens = pool.entity.tokens.minus(tokens)
161190
saveDelegationPool(pool.entity, event.block)
162191

192+
// Update DataService
193+
let dataService = getOrCreateDataService(verifierBytes, event.block.number, event.block.timestamp)
194+
assert(!dataService.isNew, "Data service does not exist.")
195+
assert(dataService.entity.tokensDelegated >= tokens, "Slash tokens exceed data service tokens delegated.")
196+
dataService.entity.tokensDelegated = dataService.entity.tokensDelegated.minus(tokens)
197+
dataService.entity.countDelegationPoolSlashEvents += 1
198+
dataService.entity.tokensSlashed = dataService.entity.tokensSlashed.plus(tokens)
199+
dataService.entity.tokensSlashedFromDelegationPools = dataService.entity.tokensSlashedFromDelegationPools.plus(tokens)
200+
saveDataService(dataService.entity, event.block)
201+
163202
// Update ServiceProvider
164203
let serviceProvider = getOrCreateServiceProvider(serviceProviderBytes, event.block.number, event.block.timestamp)
165204
assert(!serviceProvider.isNew, "Service provider does not exist.")
@@ -203,6 +242,12 @@ export function handleTokensToDelegationPoolAdded(event: TokensToDelegationPoolA
203242
pool.entity.tokens = pool.entity.tokens.plus(tokens)
204243
saveDelegationPool(pool.entity, event.block)
205244

245+
// Update DataService
246+
let dataService = getOrCreateDataService(verifierBytes, event.block.number, event.block.timestamp)
247+
assert(!dataService.isNew, "Data service does not exist.")
248+
dataService.entity.tokensDelegated = dataService.entity.tokensDelegated.plus(tokens)
249+
saveDataService(dataService.entity, event.block)
250+
206251
// Update ServiceProvider
207252
let serviceProvider = getOrCreateServiceProvider(serviceProviderBytes, event.block.number, event.block.timestamp)
208253
assert(!serviceProvider.isNew, "Service provider does not exist.")

packages/subgraph/src/handlers/legacy.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
} from "../../generated/HorizonStaking/HorizonStaking"
66
import { getOrCreateGraphNetwork, saveGraphNetwork } from "../entities/graphNetwork"
77
import { getOrCreateServiceProvider, saveServiceProvider } from "../entities/serviceProvider"
8+
import { getOrCreateDataService, saveDataService } from "../entities/dataService"
89
import { getOrCreateDelegationPool, saveDelegationPool } from "../entities/delegationPool"
910
import { config } from "../config"
1011

@@ -33,12 +34,12 @@ export function handleRebateCollected(event: RebateCollected): void {
3334
}
3435

3536
let indexerBytes = Bytes.fromHexString(indexer.toHexString()) as Bytes
36-
let verifier = Bytes.fromHexString(config.subgraphServiceAddress.toHexString()) as Bytes
37+
let dataServiceBytes = Bytes.fromHexString(config.subgraphServiceAddress.toHexString()) as Bytes
3738

3839
// Update legacy DelegationPool
3940
let pool = getOrCreateDelegationPool(
4041
indexerBytes,
41-
verifier,
42+
dataServiceBytes,
4243
event.block.number,
4344
event.block.timestamp
4445
)
@@ -49,11 +50,15 @@ export function handleRebateCollected(event: RebateCollected): void {
4950
pool.entity.tokens = pool.entity.tokens.plus(delegationRewards)
5051
saveDelegationPool(pool.entity, event.block)
5152

53+
// Update DataService
54+
let dataService = getOrCreateDataService(dataServiceBytes, event.block.number, event.block.timestamp)
55+
assert(!dataService.isNew, "Data service does not exist.")
56+
dataService.entity.tokensDelegated = dataService.entity.tokensDelegated.plus(delegationRewards)
57+
saveDataService(dataService.entity, event.block)
58+
5259
// Update ServiceProvider
5360
let serviceProvider = getOrCreateServiceProvider(indexerBytes, event.block.number, event.block.timestamp)
54-
if (serviceProvider.isNew) {
55-
return
56-
}
61+
assert(!serviceProvider.isNew, "Service provider does not exist.")
5762
serviceProvider.entity.tokensDelegated = serviceProvider.entity.tokensDelegated.plus(delegationRewards)
5863
saveServiceProvider(serviceProvider.entity, event.block)
5964

@@ -115,12 +120,12 @@ export function handleAllocationClosed(event: AllocationClosed): void {
115120
return
116121
}
117122

118-
let verifier = Bytes.fromHexString(config.subgraphServiceAddress.toHexString()) as Bytes
123+
let dataServiceBytes = Bytes.fromHexString(config.subgraphServiceAddress.toHexString()) as Bytes
119124

120125
// Get the legacy DelegationPool to read the indexer's reward cut
121126
let pool = getOrCreateDelegationPool(
122127
indexerBytes,
123-
verifier,
128+
dataServiceBytes,
124129
event.block.number,
125130
event.block.timestamp
126131
)
@@ -144,12 +149,17 @@ export function handleAllocationClosed(event: AllocationClosed): void {
144149
pool.entity.tokens = pool.entity.tokens.plus(delegationRewards)
145150
saveDelegationPool(pool.entity, event.block)
146151

152+
// Update DataService
153+
let dataService = getOrCreateDataService(dataServiceBytes, event.block.number, event.block.timestamp)
154+
assert(!dataService.isNew, "Data service does not exist.")
155+
dataService.entity.tokensDelegated = dataService.entity.tokensDelegated.plus(delegationRewards)
156+
saveDataService(dataService.entity, event.block)
157+
147158
// Update ServiceProvider
148159
let serviceProvider = getOrCreateServiceProvider(indexerBytes, event.block.number, event.block.timestamp)
149-
if (!serviceProvider.isNew) {
150-
serviceProvider.entity.tokensDelegated = serviceProvider.entity.tokensDelegated.plus(delegationRewards)
151-
saveServiceProvider(serviceProvider.entity, event.block)
152-
}
160+
assert(!serviceProvider.isNew, "Service provider does not exist.")
161+
serviceProvider.entity.tokensDelegated = serviceProvider.entity.tokensDelegated.plus(delegationRewards)
162+
saveServiceProvider(serviceProvider.entity, event.block)
153163

154164
// Update GraphNetwork
155165
let graphNetwork = getOrCreateGraphNetwork()

0 commit comments

Comments
 (0)