@@ -2,7 +2,7 @@ import * as Command from "@effect/cli/Command"
22import { Console , Effect , Schedule } from "effect"
33import { NetworkSubgraph } from "../services/network/NetworkSubgraph.js"
44import { QoSSubgraph } from "../services/qos/QoSSubgraph.js"
5- import { Display , blue } from "../utils/Display.js"
5+ import { Display , blue , green } from "../utils/Display.js"
66
77const HORIZON_VERSION = "1.7.0"
88const TEN_DAYS_IN_SECONDS = 10 * 24 * 60 * 60
@@ -38,6 +38,14 @@ export const migration = Command.make(
3838 const network = yield * NetworkSubgraph
3939 const indexerListResult = yield * network . getIndexerList ( )
4040
41+ // Build map of provisioned tokens per indexer
42+ const provisionedByIndexer = new Map < string , bigint > ( )
43+ for ( const provision of indexerListResult . provisions ) {
44+ const indexerId = provision . indexer . id . toLowerCase ( )
45+ const current = provisionedByIndexer . get ( indexerId ) ?? BigInt ( 0 )
46+ provisionedByIndexer . set ( indexerId , current + BigInt ( provision . tokensProvisioned ) )
47+ }
48+
4149 const indexerCount = indexerListResult . indexers . length
4250 const indexerWithAllocationsCount = indexerListResult . indexers . filter ( ( indexer ) =>
4351 indexer . allocations . length > 0
@@ -148,37 +156,39 @@ export const migration = Command.make(
148156 }
149157 }
150158
151- // Display query volume coverage section
152- yield * Display . section ( "Query volume coverage (last 10 days)" )
153-
159+ // Calculate total network stake metrics
160+ const totalStaked = indexerListResult . indexers . reduce ( ( acc , indexer ) => {
161+ return acc + BigInt ( indexer . stakedTokens ?? 0 )
162+ } , BigInt ( 0 ) )
163+ const totalProvisioned = indexerListResult . provisions . reduce ( ( acc , provision ) => {
164+ return acc + BigInt ( provision . tokensProvisioned )
165+ } , BigInt ( 0 ) )
166+ const stakePct = totalStaked > 0
167+ ? ( ( Number ( totalProvisioned ) / Number ( totalStaked ) ) * 100 ) . toFixed ( 2 )
168+ : "N/A"
169+ const stakeDisplay = totalStaked > 0
170+ ? `${ stakePct } % (${ formatGRT ( totalProvisioned ) } / ${ formatGRT ( totalStaked ) } )`
171+ : "N/A"
172+
173+ // Calculate query volume coverage
174+ let queryVolumeDisplay = "N/A (QOS_SUBGRAPH_URL not configured)"
154175 if ( qosConfigured && volumeByDay . size > 0 ) {
155- const sortedDays = Array . from ( volumeByDay . keys ( ) ) . sort ( ( a , b ) => Number ( a ) - Number ( b ) )
156176 let totalQueries = BigInt ( 0 )
157177 let horizonQueries = BigInt ( 0 )
158-
159- for ( const day of sortedDays ) {
160- const dayData = volumeByDay . get ( day ) !
178+ for ( const dayData of volumeByDay . values ( ) ) {
161179 totalQueries += dayData . total
162180 horizonQueries += dayData . horizon
163-
164- const date = new Date ( Number ( day ) * 1000 ) . toISOString ( ) . split ( "T" ) [ 0 ]
165- const percentage = dayData . total > 0
166- ? ( ( Number ( dayData . horizon ) / Number ( dayData . total ) ) * 100 ) . toFixed ( 2 )
167- : "0.00"
168- yield * Display . keyValue (
169- ` ${ date } ` ,
170- `${ percentage } % (${ formatNumber ( dayData . horizon ) } / ${ formatNumber ( dayData . total ) } )`
171- )
172181 }
173-
174- const overallPercentage = totalQueries > 0
182+ const queryPct = totalQueries > 0
175183 ? ( ( Number ( horizonQueries ) / Number ( totalQueries ) ) * 100 ) . toFixed ( 2 )
176184 : "0.00"
177- yield * Display . keyValue ( "Overall" , `${ overallPercentage } % horizon coverage` )
178- } else {
179- yield * Console . log ( " QOS_SUBGRAPH_URL not configured" )
185+ queryVolumeDisplay = `${ queryPct } % (${ formatNumber ( horizonQueries ) } / ${ formatNumber ( totalQueries ) } )`
180186 }
181187
188+ yield * Display . section ( "Horizon coverage" )
189+ yield * Display . keyValue ( "Stake provisioned" , stakeDisplay )
190+ yield * Display . keyValue ( "Query volume (10d)" , queryVolumeDisplay )
191+
182192 yield * Display . section ( "Active indexers details" )
183193
184194 // Group indexers by version
@@ -198,32 +208,51 @@ export const migration = Command.make(
198208 return compareVersions ( b , a ) // descending order
199209 } )
200210
201- // Display grouped by version with query volume
211+ // Display grouped by version with query volume and stake
202212 for ( const version of sortedVersions ) {
203213 const indexers = indexersByVersion [ version ]
204214
205215 // Calculate total volume for this version
206216 const versionVolume = indexers . reduce ( ( acc , indexer ) => {
207217 return acc + ( volumeByIndexer . get ( indexer . id . toLowerCase ( ) ) ?? BigInt ( 0 ) )
208218 } , BigInt ( 0 ) )
209- const versionPercentage = qosConfigured && grandTotalQueries > 0
219+ const versionQueryPct = qosConfigured && grandTotalQueries > 0
210220 ? `${ ( ( Number ( versionVolume ) / Number ( grandTotalQueries ) ) * 100 ) . toFixed ( 2 ) } %`
211221 : "N/A"
212222
223+ // Calculate total stake percentage for this version
224+ const versionStaked = indexers . reduce ( ( acc , indexer ) => {
225+ return acc + BigInt ( indexer . stakedTokens ?? 0 )
226+ } , BigInt ( 0 ) )
227+ const versionProvisioned = indexers . reduce ( ( acc , indexer ) => {
228+ return acc + ( provisionedByIndexer . get ( indexer . id . toLowerCase ( ) ) ?? BigInt ( 0 ) )
229+ } , BigInt ( 0 ) )
230+ const versionStakePct = versionStaked > 0
231+ ? `${ ( ( Number ( versionProvisioned ) / Number ( versionStaked ) ) * 100 ) . toFixed ( 2 ) } %`
232+ : "N/A"
233+
213234 yield * Console . log (
214235 `\n Version ${ version } (${ indexers . length } indexer${
215236 indexers . length === 1 ? "" : "s"
216- } ) - ${ blue ( versionPercentage ) } :`
237+ } ) - ${ blue ( versionQueryPct ) } ${ green ( versionStakePct ) } :`
217238 )
218239
219240 for ( const indexer of indexers ) {
220241 const indexerVolume = volumeByIndexer . get ( indexer . id . toLowerCase ( ) ) ?? BigInt ( 0 )
221- const volumePercentage = qosConfigured && grandTotalQueries > 0
242+ const queryPct = qosConfigured && grandTotalQueries > 0
222243 ? `${ ( ( Number ( indexerVolume ) / Number ( grandTotalQueries ) ) * 100 ) . toFixed ( 2 ) } %`
223244 : "N/A"
224- yield * Display . tripleString (
245+
246+ const staked = BigInt ( indexer . stakedTokens ?? 0 )
247+ const provisioned = provisionedByIndexer . get ( indexer . id . toLowerCase ( ) ) ?? BigInt ( 0 )
248+ const stakePct = staked > 0
249+ ? `${ ( ( Number ( provisioned ) / Number ( staked ) ) * 100 ) . toFixed ( 2 ) } %`
250+ : "N/A"
251+
252+ yield * Display . quadString (
225253 indexer . id ,
226- volumePercentage ,
254+ queryPct ,
255+ stakePct ,
227256 indexer . url ?? "N/A"
228257 )
229258 }
@@ -244,6 +273,18 @@ function formatNumber(n: bigint): string {
244273 return n . toLocaleString ( )
245274}
246275
276+ function formatGRT ( n : bigint ) : string {
277+ const grt = Number ( n ) / 1e18
278+ if ( grt >= 1_000_000_000 ) {
279+ return `${ ( grt / 1_000_000_000 ) . toFixed ( 2 ) } B GRT`
280+ } else if ( grt >= 1_000_000 ) {
281+ return `${ ( grt / 1_000_000 ) . toFixed ( 2 ) } M GRT`
282+ } else if ( grt >= 1_000 ) {
283+ return `${ ( grt / 1_000 ) . toFixed ( 2 ) } K GRT`
284+ }
285+ return `${ grt . toFixed ( 2 ) } GRT`
286+ }
287+
247288function parseVersion ( v : string ) {
248289 return v . split ( "." ) . map ( Number )
249290}
0 commit comments