Skip to content

Commit 30e831a

Browse files
committed
fix: operator and delegator fees can be set without pre existing other
entities Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
1 parent 391d74e commit 30e831a

5 files changed

Lines changed: 66 additions & 19 deletions

File tree

packages/subgraph/schema.graphql

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,16 @@ type Provision @entity(immutable: false) {
228228
}
229229

230230
type ProvisionFeeCut @entity(immutable: false) {
231-
"Composite ID: provision-paymentType"
231+
"Composite ID: serviceProvider-dataService-paymentType"
232232
id: Bytes!
233233

234234
# Relationships
235235
"Provision this fee cut belongs to"
236-
provision: Provision!
236+
provision: Provision
237+
"Service provider"
238+
serviceProvider: ServiceProvider
239+
"Data service"
240+
dataService: DataService
237241

238242
# State
239243
"Payment type (maps to PaymentTypes enum: 0 = QueryFee, 1 = IndexingFee, 2 = IndexingReward, ...)"
@@ -318,9 +322,9 @@ type OperatorAuthorization @entity(immutable: false) {
318322
"Operator that is authorized"
319323
operator: Operator!
320324
"Service provider that granted the authorization"
321-
serviceProvider: ServiceProvider!
325+
serviceProvider: ServiceProvider
322326
"Data service this authorization applies to"
323-
dataService: DataService!
327+
dataService: DataService
324328

325329
# State
326330
"Whether the operator is currently authorized"

packages/subgraph/src/entities/provisionFeeCut.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export function getOrCreateProvisionFeeCut(
3131

3232
if (entity == null) {
3333
entity = new ProvisionFeeCut(id)
34+
entity.serviceProvider = serviceProvider
35+
entity.dataService = dataService
3436
entity.provision = getProvisionId(serviceProvider, dataService)
3537
entity.paymentType = paymentType
3638
entity.feeCut = BIGINT_ZERO

packages/subgraph/tests/feeCut.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,35 @@ describe("DelegationFeeCutSet", () => {
123123

124124
assert.entityCount("ProvisionFeeCut", 1)
125125
assert.fieldEquals("ProvisionFeeCut", entityId, "provision", provisionId)
126+
assert.fieldEquals("ProvisionFeeCut", entityId, "serviceProvider", SP_ADDRESS.toHexString())
127+
assert.fieldEquals("ProvisionFeeCut", entityId, "dataService", VERIFIER_ADDRESS.toHexString())
126128
assert.fieldEquals("ProvisionFeeCut", entityId, "paymentType", PAYMENT_TYPE_QUERY_FEE.toString())
127129
assert.fieldEquals("ProvisionFeeCut", entityId, "feeCut", feeCut.toString())
128130
assert.fieldEquals("ProvisionFeeCut", entityId, "updatedAtBlock", "300")
129131
assert.fieldEquals("ProvisionFeeCut", entityId, "updatedAt", "3000")
130132
})
131133

134+
test("creates ProvisionFeeCut without existing provision", () => {
135+
// Set fee cut WITHOUT creating provision first
136+
let feeCut = BigInt.fromI32(100000) // 10% in PPM
137+
let event = createDelegationFeeCutSetEvent(
138+
SP_ADDRESS,
139+
VERIFIER_ADDRESS,
140+
PAYMENT_TYPE_QUERY_FEE,
141+
feeCut
142+
)
143+
handleDelegationFeeCutSet(event)
144+
145+
let entityId = getFeeCutIdString(SP_ADDRESS, VERIFIER_ADDRESS, PAYMENT_TYPE_QUERY_FEE)
146+
147+
// Entity should exist with serviceProvider and dataService set
148+
assert.entityCount("ProvisionFeeCut", 1)
149+
assert.fieldEquals("ProvisionFeeCut", entityId, "serviceProvider", SP_ADDRESS.toHexString())
150+
assert.fieldEquals("ProvisionFeeCut", entityId, "dataService", VERIFIER_ADDRESS.toHexString())
151+
assert.fieldEquals("ProvisionFeeCut", entityId, "paymentType", PAYMENT_TYPE_QUERY_FEE.toString())
152+
assert.fieldEquals("ProvisionFeeCut", entityId, "feeCut", feeCut.toString())
153+
})
154+
132155
test("creates separate entities for different payment types", () => {
133156
setupServiceProviderAndProvision()
134157

packages/tools/src/validation/onchain/fee-cuts.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@ import {
1818

1919
interface ProvisionFeeCut {
2020
id: string
21-
provision: {
22-
id: string
23-
serviceProvider: { id: string }
24-
dataService: { id: string }
25-
}
21+
serviceProvider: { id: string } | null
22+
dataService: { id: string } | null
2623
paymentType: number
2724
feeCut: string
2825
}
@@ -37,11 +34,8 @@ async function main(): Promise<number> {
3734
subgraphUrl,
3835
`{ provisionFeeCuts(first: 1000) {
3936
id
40-
provision {
41-
id
42-
serviceProvider { id }
43-
dataService { id }
44-
}
37+
serviceProvider { id }
38+
dataService { id }
4539
paymentType
4640
feeCut
4741
} }`
@@ -55,11 +49,18 @@ async function main(): Promise<number> {
5549
console.log("=== Comparing ProvisionFeeCuts against on-chain state ===")
5650
let mismatches = 0
5751
let matches = 0
52+
let skipped = 0
5853

5954
for (const feeCut of feeCuts) {
55+
// Skip if serviceProvider or dataService entity doesn't exist yet
56+
if (!feeCut.serviceProvider || !feeCut.dataService) {
57+
skipped++
58+
continue
59+
}
60+
6061
const onChainFeeCut = await getDelegationFeeCut(
61-
feeCut.provision.serviceProvider.id,
62-
feeCut.provision.dataService.id,
62+
feeCut.serviceProvider.id,
63+
feeCut.dataService.id,
6364
feeCut.paymentType
6465
)
6566

@@ -69,7 +70,7 @@ async function main(): Promise<number> {
6970
if (fieldMismatches.length > 0) {
7071
mismatches++
7172
console.log(
72-
`MISMATCH: ${feeCut.provision.serviceProvider.id} -> ${feeCut.provision.dataService.id} (paymentType=${feeCut.paymentType})`
73+
`MISMATCH: ${feeCut.serviceProvider.id} -> ${feeCut.dataService.id} (paymentType=${feeCut.paymentType})`
7374
)
7475
for (const m of fieldMismatches) {
7576
console.log(m.message)
@@ -82,6 +83,11 @@ async function main(): Promise<number> {
8283
await delay()
8384
}
8485

86+
if (skipped > 0) {
87+
console.log(` Skipped ${skipped} fee cuts (serviceProvider or dataService entity doesn't exist)`)
88+
console.log("")
89+
}
90+
8591
// Summary
8692
const results: ValidationResult[] = [{ label: "ProvisionFeeCuts", total: feeCuts.length, matches, mismatches }]
8793
printValidationSummary(results)

packages/tools/src/validation/onchain/operators.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import {
1818
interface OperatorAuthorization {
1919
id: string
2020
operator: { id: string }
21-
serviceProvider: { id: string }
22-
dataService: { id: string }
21+
serviceProvider: { id: string } | null
22+
dataService: { id: string } | null
2323
allowed: boolean
2424
}
2525

@@ -53,7 +53,14 @@ async function main(): Promise<number> {
5353
let mismatches = 0
5454
let matches = 0
5555

56+
let skipped = 0
5657
for (const auth of authorizations) {
58+
// Skip if serviceProvider or dataService entity doesn't exist yet
59+
if (!auth.serviceProvider || !auth.dataService) {
60+
skipped++
61+
continue
62+
}
63+
5764
const onChainAllowed = await isAuthorized(
5865
auth.serviceProvider.id,
5966
auth.dataService.id,
@@ -75,6 +82,11 @@ async function main(): Promise<number> {
7582
await delay()
7683
}
7784

85+
if (skipped > 0) {
86+
console.log(` Skipped ${skipped} authorizations (serviceProvider or dataService entity doesn't exist)`)
87+
console.log("")
88+
}
89+
7890
// Summary
7991
const results: ValidationResult[] = [{ label: "OperatorAuthorizations", total: authorizations.length, matches, mismatches }]
8092
printValidationSummary(results)

0 commit comments

Comments
 (0)