From 762c234bcf563726f8de176d9fbfc4ca1aad91e8 Mon Sep 17 00:00:00 2001 From: cargopete Date: Tue, 9 Jun 2026 14:36:08 +0300 Subject: [PATCH] feat(horizon): expose Provision.delegatedTokensActive as APR/APY denominator --- schema.graphql | 2 ++ src/mappings/helpers/helpers.ts | 2 ++ src/mappings/horizonStaking.ts | 3 +++ 3 files changed, 7 insertions(+) diff --git a/schema.graphql b/schema.graphql index 785df192..7eae1ccd 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1002,6 +1002,8 @@ type Provision @entity(immutable: false) { delegatedTokens: BigInt! "Tokens delegated that are thawing from the provision" delegatedThawingTokens: BigInt! + "Actively-earning delegated tokens: delegatedTokens minus delegatedThawingTokens. This is the correct denominator for delegation APR/APY: it excludes both in-period thawing and completed-but-not-yet-withdrawn delegation, since thawed-but-unwithdrawn tokens remain counted in delegatedThawingTokens until withdrawal. Prefer this over delegatedTokens when computing returns." + delegatedTokensActive: BigInt! "Total shares of the delegator pool" delegatorShares: BigInt! "Exchange rate of tokens received for each share" diff --git a/src/mappings/helpers/helpers.ts b/src/mappings/helpers/helpers.ts index 4d814039..3d182ca9 100644 --- a/src/mappings/helpers/helpers.ts +++ b/src/mappings/helpers/helpers.ts @@ -256,6 +256,7 @@ export function createOrLoadProvision(indexerAddress: Bytes, verifierAddress: By provision.delegatorShares = BigInt.fromI32(0) provision.delegationExchangeRate = BigInt.fromI32(0).toBigDecimal() } + provision.delegatedTokensActive = provision.delegatedTokens.minus(provision.delegatedThawingTokens) provision.thawingUntil = BigInt.fromI32(0) provision.ownStakeRatio = BigInt.fromI32(0).toBigDecimal() provision.delegatedStakeRatio = BigInt.fromI32(0).toBigDecimal() @@ -1168,6 +1169,7 @@ export function calculateOverdelegationDilutionForProvision(provision: Provision } export function updateAdvancedProvisionMetrics(provision: Provision): Provision { + provision.delegatedTokensActive = provision.delegatedTokens.minus(provision.delegatedThawingTokens) provision.ownStakeRatio = calculateOwnStakeRatioForProvision(provision as Provision) provision.delegatedStakeRatio = calculateDelegatedStakeRatioForProvision(provision as Provision) provision.indexingRewardEffectiveCut = calculateIndexingRewardEffectiveCutForProvision(provision as Provision) diff --git a/src/mappings/horizonStaking.ts b/src/mappings/horizonStaking.ts index 69901ca8..cd9904ec 100644 --- a/src/mappings/horizonStaking.ts +++ b/src/mappings/horizonStaking.ts @@ -553,6 +553,9 @@ export function handleDelegatedTokensWithdrawn(event: DelegatedTokensWithdrawn): // might want to track locked/thawing tokens in provision too provision.delegatedTokens = provision.delegatedTokens.minus(event.params.tokens) provision.delegatedThawingTokens = provision.delegatedThawingTokens.minus(event.params.tokens) + // Withdrawal removes equal amounts from both totals, so the actively-earning base is unchanged; + // recompute explicitly to keep the field consistent (this handler bypasses updateAdvancedProvisionMetrics). + provision.delegatedTokensActive = provision.delegatedTokens.minus(provision.delegatedThawingTokens) provision.save() let indexerID = event.params.serviceProvider.toHexString()