Skip to content

Commit 493b84a

Browse files
committed
feat: show migration stake
Signed-off-by: Tomás Migone <tomas@edgeandnode.com>
1 parent 7441e20 commit 493b84a

File tree

3 files changed

+83
-28
lines changed

3 files changed

+83
-28
lines changed

packages/cli/src/commands/migration.ts

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as Command from "@effect/cli/Command"
22
import { Console, Effect, Schedule } from "effect"
33
import { NetworkSubgraph } from "../services/network/NetworkSubgraph.js"
44
import { QoSSubgraph } from "../services/qos/QoSSubgraph.js"
5-
import { Display, blue } from "../utils/Display.js"
5+
import { Display, blue, green } from "../utils/Display.js"
66

77
const HORIZON_VERSION = "1.7.0"
88
const 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+
247288
function parseVersion(v: string) {
248289
return v.split(".").map(Number)
249290
}

packages/cli/src/services/network/queries/IndexerList.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ query IndexerList {
22
indexers(first: 1000) {
33
id
44
url
5+
stakedTokens
56
allocations {
67
createdAt
78
}
@@ -10,5 +11,6 @@ query IndexerList {
1011
indexer {
1112
id
1213
}
14+
tokensProvisioned
1315
}
1416
}

packages/cli/src/utils/Display.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ export class Display {
6969
return Console.log(` ${formattedFirst} ${formattedSecond} ${formattedThird}`)
7070
}
7171

72+
static quadString(first: string, second: string, third: string, fourth: string): Effect.Effect<void, never> {
73+
const formattedFirst = Display.colorize(first.padEnd(44), "cyan")
74+
const formattedSecond = Display.colorize(second.padEnd(10), "blue")
75+
const formattedThird = Display.colorize(third.padEnd(10), "green")
76+
const formattedFourth = Display.colorize(fourth.padEnd(30), "white")
77+
return Console.log(` ${formattedFirst} ${formattedSecond} ${formattedThird} ${formattedFourth}`)
78+
}
79+
7280
static section(title: string): Effect.Effect<void, never> {
7381
return Effect.gen(function*() {
7482
yield* Console.log("")
@@ -164,3 +172,7 @@ function bigintToString(value: bigint, token: boolean = false): string {
164172
export function blue(text: string): string {
165173
return Display.colorize(text, "blue")
166174
}
175+
176+
export function green(text: string): string {
177+
return Display.colorize(text, "green")
178+
}

0 commit comments

Comments
 (0)