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
59 changes: 51 additions & 8 deletions packages/subgraph/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ type ServiceProvider @entity(immutable: false) {
"Service provider address"
id: Bytes!

# Relationships
"Provisions created by this service provider"
provisions: [Provision!]! @derivedFrom(field: "serviceProvider")
"Delegation pools for this service provider"
delegationPools: [DelegationPool!]! @derivedFrom(field: "serviceProvider")
"Provision thaw requests for this service provider"
provisionThawRequests: [ProvisionThawRequest!]! @derivedFrom(field: "serviceProvider")

# Counts
"Number of active provisions"
countProvisions: Int!
Expand Down Expand Up @@ -73,14 +81,6 @@ type ServiceProvider @entity(immutable: false) {
"Tokens slashed from delegation pools"
tokensSlashedFromDelegationPools: BigInt!

# Provisions
"Provisions created by this service provider"
provisions: [Provision!]! @derivedFrom(field: "serviceProvider")

# Delegation pools
"Delegation pools for this service provider"
delegationPools: [DelegationPool!]! @derivedFrom(field: "serviceProvider")

# Metadata
"Block number when entity was created"
createdAtBlock: BigInt!
Expand All @@ -101,6 +101,8 @@ type DataService @entity(immutable: false) {
provisions: [Provision!]! @derivedFrom(field: "dataService")
"Delegation pools for this data service"
delegationPools: [DelegationPool!]! @derivedFrom(field: "dataService")
"Provision thaw requests for this data service"
provisionThawRequests: [ProvisionThawRequest!]! @derivedFrom(field: "dataService")

# Counts
"Active service providers with provisions to this data service"
Expand Down Expand Up @@ -185,6 +187,8 @@ type Provision @entity(immutable: false) {
serviceProvider: ServiceProvider!
"Data service (verifier)"
dataService: DataService!
"Thaw requests for this provision"
thawRequests: [ProvisionThawRequest!]! @derivedFrom(field: "provision")

# Tokens
"Tokens currently provisioned"
Expand Down Expand Up @@ -216,3 +220,42 @@ type Provision @entity(immutable: false) {
"Timestamp when entity was last updated"
updatedAt: BigInt!
}

type ProvisionThawRequest @entity(immutable: false) {
"Thaw request ID (bytes32) emitted by ThawRequestCreated event"
id: Bytes!

# Relationships
"Provision being thawed"
provision: Provision!
"Service provider"
serviceProvider: ServiceProvider!
"Data service (verifier)"
dataService: DataService!

# State
"Shares being thawed"
shares: BigInt!
"Timestamp when thaw completes"
thawingUntil: BigInt!
"Thawing nonce at time of creation"
thawingNonce: BigInt!
"Tokens withdrawn (set on fulfillment, null while pending)"
tokensWithdrawn: BigInt

# Status
"False if invalidated by slashing"
valid: Boolean!
"True when tokens have been withdrawn"
fulfilled: Boolean!

# Metadata
"Block number when entity was created"
createdAtBlock: BigInt!
"Timestamp when entity was created"
createdAt: BigInt!
"Block number when entity was last updated"
updatedAtBlock: BigInt!
"Timestamp when entity was last updated"
updatedAt: BigInt!
}
3 changes: 2 additions & 1 deletion packages/subgraph/src/entities/delegationPool.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"
import { DelegationPool } from "../../generated/schema"
import { BIGINT_ZERO } from "../common/constants"
import { twoPartId } from "../common/ids"

export function getDelegationPoolId(serviceProvider: Bytes, dataService: Bytes): Bytes {
return serviceProvider.concat(dataService)
return twoPartId(serviceProvider, dataService)
}

export class DelegationPoolResult {
Expand Down
3 changes: 2 additions & 1 deletion packages/subgraph/src/entities/provision.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"
import { Provision } from "../../generated/schema"
import { BIGINT_ZERO } from "../common/constants"
import { twoPartId } from "../common/ids"

export function getProvisionId(serviceProvider: Bytes, dataService: Bytes): Bytes {
return serviceProvider.concat(dataService)
return twoPartId(serviceProvider, dataService)
}

export class ProvisionResult {
Expand Down
52 changes: 52 additions & 0 deletions packages/subgraph/src/entities/provisionThawRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { BigInt, Bytes, ethereum } from "@graphprotocol/graph-ts"
import { ProvisionThawRequest } from "../../generated/schema"
import { getProvisionId } from "./provision"

export class ProvisionThawRequestResult {
entity: ProvisionThawRequest
isNew: boolean

constructor(entity: ProvisionThawRequest, isNew: boolean) {
this.entity = entity
this.isNew = isNew
}
}

export function getOrCreateProvisionThawRequest(
id: Bytes,
serviceProvider: Bytes,
dataService: Bytes,
blockNumber: BigInt,
timestamp: BigInt
): ProvisionThawRequestResult {
let entity = ProvisionThawRequest.load(id)
let isNew = entity == null

if (entity == null) {
entity = new ProvisionThawRequest(id)
entity.provision = getProvisionId(serviceProvider, dataService)
entity.serviceProvider = serviceProvider
entity.dataService = dataService
entity.shares = BigInt.zero()
entity.thawingUntil = BigInt.zero()
entity.thawingNonce = BigInt.zero()
entity.tokensWithdrawn = null
entity.valid = true
entity.fulfilled = false
entity.createdAtBlock = blockNumber
entity.createdAt = timestamp
entity.updatedAtBlock = blockNumber
entity.updatedAt = timestamp
}

return new ProvisionThawRequestResult(entity, isNew)
}

export function saveProvisionThawRequest(
thawRequest: ProvisionThawRequest,
block: ethereum.Block
): void {
thawRequest.updatedAtBlock = block.number
thawRequest.updatedAt = block.timestamp
thawRequest.save()
}
72 changes: 72 additions & 0 deletions packages/subgraph/src/handlers/thawRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Bytes, log } from "@graphprotocol/graph-ts"
import {
ThawRequestCreated,
ThawRequestFulfilled,
} from "../../generated/HorizonStaking/HorizonStaking"
import { ProvisionThawRequest } from "../../generated/schema"
import {
getOrCreateProvisionThawRequest,
saveProvisionThawRequest,
} from "../entities/provisionThawRequest"

// ThawRequestType enum values from the contract
// 0 = Provision
// 1 = Delegation
const THAW_REQUEST_TYPE_PROVISION = 0

/**
* Handles ThawRequestCreated event.
* Creates a ProvisionThawRequest entity when a service provider initiates thawing.
* Only handles provision thaw requests (type 0), ignores delegation thaw requests.
*/
export function handleThawRequestCreated(event: ThawRequestCreated): void {
if (event.params.requestType != THAW_REQUEST_TYPE_PROVISION) {
return
}

let serviceProviderBytes = Bytes.fromHexString(
event.params.serviceProvider.toHexString()
) as Bytes
let dataServiceBytes = Bytes.fromHexString(
event.params.verifier.toHexString()
) as Bytes

let thawRequest = getOrCreateProvisionThawRequest(
event.params.thawRequestId,
serviceProviderBytes,
dataServiceBytes,
event.block.number,
event.block.timestamp
)

assert(thawRequest.isNew, "Thaw request already exists.")
thawRequest.entity.shares = event.params.shares
thawRequest.entity.thawingUntil = event.params.thawingUntil
thawRequest.entity.thawingNonce = event.params.nonce

saveProvisionThawRequest(thawRequest.entity, event.block)
}

/**
* Handles ThawRequestFulfilled event.
* Updates a ProvisionThawRequest entity when thawed tokens are withdrawn.
* Only handles provision thaw requests (type 0), ignores delegation thaw requests.
*/
export function handleThawRequestFulfilled(event: ThawRequestFulfilled): void {
if (event.params.requestType != THAW_REQUEST_TYPE_PROVISION) {
return
}

// Load directly since ThawRequestFulfilled doesn't include serviceProvider/dataService
let thawRequest = ProvisionThawRequest.load(event.params.thawRequestId)
if (thawRequest == null) {
log.critical("Could not find thaw request: {}.", [event.params.thawRequestId.toHexString()])
return
}

thawRequest.tokensWithdrawn = event.params.tokens
thawRequest.valid = event.params.valid
thawRequest.fulfilled = true

saveProvisionThawRequest(thawRequest, event.block)
}
4 changes: 4 additions & 0 deletions packages/subgraph/src/mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export {
handleRebateCollected,
handleAllocationClosed
} from "./handlers/legacy"
export {
handleThawRequestCreated,
handleThawRequestFulfilled
} from "./handlers/thawRequest"
9 changes: 7 additions & 2 deletions packages/subgraph/subgraph.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ dataSources:
entities:
- GraphNetwork
- ServiceProvider
- DataService
- Provision
- DelegationPool
- Delegator
- Delegation
- ProvisionThawRequest
abis:
- name: HorizonStaking
file: ./abis/HorizonStaking.json
Expand Down Expand Up @@ -59,6 +59,11 @@ dataSources:
handler: handleDelegatedTokensWithdrawn
- event: DelegationSlashed(indexed address,indexed address,uint256)
handler: handleDelegationSlashed
# Thaw request events
- event: ThawRequestCreated(indexed uint8,indexed address,indexed address,address,uint256,uint64,bytes32,uint256)
handler: handleThawRequestCreated
- event: ThawRequestFulfilled(indexed uint8,indexed bytes32,uint256,uint256,uint64,bool)
handler: handleThawRequestFulfilled
# Legacy delegation reward events (HorizonStakingExtension)
- event: RebateCollected(address,indexed address,indexed bytes32,indexed address,uint256,uint256,uint256,uint256,uint256,uint256,uint256)
handler: handleRebateCollected
Expand Down
Loading
Loading