diff --git a/scripts/cc-cli/src/commands/chill.ts b/scripts/cc-cli/src/commands/chill.ts index 93b9376014..7db847faa9 100644 --- a/scripts/cc-cli/src/commands/chill.ts +++ b/scripts/cc-cli/src/commands/chill.ts @@ -5,7 +5,7 @@ import { initKeyringPair, } from "../utils/account"; import { chill } from "../utils/validate"; -import { getStatus, requireStatus } from "../utils/status"; +import { getValidatorStatus, requireStatus } from "../utils/validatorStatus"; export function makeChillCommand() { const cmd = new Command("chill"); @@ -23,13 +23,13 @@ async function chillAction(options: OptionValues) { const controllerKeyring = initKeyringPair(controllerSeed); const controllerAddress = controllerKeyring.address; - const controllerStatus = await getStatus(controllerAddress, api); + const controllerStatus = await getValidatorStatus(controllerAddress, api); if (!controllerStatus.stash) { console.error(`Cannot chill, ${controllerAddress} is not staked`); process.exit(1); } - const stashStatus = await getStatus(controllerStatus.stash, api); + const stashStatus = await getValidatorStatus(controllerStatus.stash, api); requireStatus(stashStatus, "validating"); diff --git a/scripts/cc-cli/src/commands/status.ts b/scripts/cc-cli/src/commands/status.ts index 196d694aa4..437b809eb7 100644 --- a/scripts/cc-cli/src/commands/status.ts +++ b/scripts/cc-cli/src/commands/status.ts @@ -1,12 +1,20 @@ import { Command, OptionValues } from "commander"; import { newApi } from "../api"; -import { getStatus, printValidatorStatus } from "../utils/status"; -import { parseAddressOrExit, requiredInput } from "../utils/parsing"; +import { + getValidatorStatus, + printValidatorStatus, +} from "../utils/validatorStatus"; +import { parseAddressOrExit, parseBoolean } from "../utils/parsing"; +import { getChainStatus, printChainStatus } from "../utils/chainStatus"; export function makeStatusCommand() { const cmd = new Command("status"); cmd.description("Get staking status for an address"); - cmd.option("-a, --address [address]", "Address to get status for"); + cmd.option( + "--validator [address]", + "Validator stash address to get status for" + ); + cmd.option("--chain", "Show chain status"); cmd.action(statusAction); return cmd; } @@ -14,17 +22,24 @@ export function makeStatusCommand() { async function statusAction(options: OptionValues) { const { api } = await newApi(options.url); - // Check options - const address = parseAddressOrExit( - requiredInput( - options.address, - "Failed to show validator status: Must specify an address" - ) - ); + const showValidatorStatus = parseBoolean(options.validator); + let showChainStatus = parseBoolean(options.chain); + + if (!showValidatorStatus && !showChainStatus) { + showChainStatus = true; + } - const validatorStatus = await getStatus(address, api); + if (showChainStatus) { + const chainStatus = await getChainStatus(api); + printChainStatus(chainStatus); + } - await printValidatorStatus(validatorStatus, api); + if (showValidatorStatus) { + const validator = parseAddressOrExit(options.validator); + const validatorStatus = await getValidatorStatus(validator, api); + console.log(`Validator ${validator}:`); + await printValidatorStatus(validatorStatus, api); + } process.exit(0); } diff --git a/scripts/cc-cli/src/commands/unbond.ts b/scripts/cc-cli/src/commands/unbond.ts index c49649f333..dbf75c043f 100644 --- a/scripts/cc-cli/src/commands/unbond.ts +++ b/scripts/cc-cli/src/commands/unbond.ts @@ -5,11 +5,11 @@ import { initKeyringPair, } from "../utils/account"; import { getBalance } from "../utils/balance"; -import { getStatus, requireStatus } from "../utils/status"; -import { requireEnoughFundsToSend, signSendAndWatch } from "../utils/tx"; import { ApiPromise, BN } from "creditcoin-js"; import { promptContinue } from "../utils/promptContinue"; import { parseAmountOrExit, requiredInput } from "../utils/parsing"; +import { getValidatorStatus, requireStatus } from "../utils/validatorStatus"; +import { requireEnoughFundsToSend, signSendAndWatch } from "../utils/tx"; export function makeUnbondCommand() { const cmd = new Command("unbond"); @@ -31,14 +31,14 @@ async function unbondAction(options: OptionValues) { const controllerKeyring = initKeyringPair(controllerSeed); const controllerAddress = controllerKeyring.address; - const controllerStatus = await getStatus(controllerAddress, api); + const controllerStatus = await getValidatorStatus(controllerAddress, api); if (!controllerStatus.stash) { console.error( `Cannot unbond, ${controllerAddress} is not a controller account` ); process.exit(1); } - const stashStatus = await getStatus(controllerStatus.stash, api); + const stashStatus = await getValidatorStatus(controllerStatus.stash, api); requireStatus(stashStatus, "bonded"); // Check if amount specified exceeds total bonded funds diff --git a/scripts/cc-cli/src/commands/withdrawUnbonded.ts b/scripts/cc-cli/src/commands/withdrawUnbonded.ts index 02d91ebf77..2860b1fc66 100644 --- a/scripts/cc-cli/src/commands/withdrawUnbonded.ts +++ b/scripts/cc-cli/src/commands/withdrawUnbonded.ts @@ -1,6 +1,6 @@ import { Command, OptionValues } from "commander"; import { newApi } from "../api"; -import { getStatus, requireStatus } from "../utils/status"; +import { getValidatorStatus, requireStatus } from "../utils/validatorStatus"; import { getControllerSeedFromEnvOrPrompt, initKeyringPair, @@ -20,7 +20,7 @@ async function withdrawUnbondedAction(options: OptionValues) { const controllerSeed = await getControllerSeedFromEnvOrPrompt(); const controller = initKeyringPair(controllerSeed); - const controllerStatus = await getStatus(controller.address, api); + const controllerStatus = await getValidatorStatus(controller.address, api); if (!controllerStatus.stash) { console.error( @@ -29,7 +29,7 @@ async function withdrawUnbondedAction(options: OptionValues) { process.exit(1); } - const status = await getStatus(controllerStatus.stash, api); + const status = await getValidatorStatus(controllerStatus.stash, api); requireStatus( status, "canWithdraw", diff --git a/scripts/cc-cli/src/utils/chainStatus.ts b/scripts/cc-cli/src/utils/chainStatus.ts new file mode 100644 index 0000000000..06ecc117e1 --- /dev/null +++ b/scripts/cc-cli/src/utils/chainStatus.ts @@ -0,0 +1,53 @@ +import { ApiPromise } from "creditcoin-js"; +import Table from "cli-table3"; + +interface ChainStatus { + name: string; + bestNumber: number; + bestFinalizedNumber: number; + eraInfo: EraInfo; +} + +export async function getChainStatus(api: ApiPromise): Promise { + const bestNumber = await api.derive.chain.bestNumber(); + const bestFinalizedNumber = await api.derive.chain.bestNumberFinalized(); + const eraInfo = await getEraInfo(api); + return { + name: api.runtimeVersion.specName.toString(), + bestNumber: bestNumber.toNumber(), + bestFinalizedNumber: bestFinalizedNumber.toNumber(), + eraInfo, + }; +} + +interface EraInfo { + era: number; + currentSession: number; + sessionsPerEra: number; +} + +async function getEraInfo(api: ApiPromise): Promise { + const session = await api.derive.session.info(); + return { + era: session.activeEra.toNumber(), + currentSession: + (session.currentIndex.toNumber() % session.sessionsPerEra.toNumber()) + 1, + sessionsPerEra: session.sessionsPerEra.toNumber(), + }; +} + +export function printChainStatus(status: ChainStatus) { + const { eraInfo } = status; + const table = new Table({ + head: [status.name], + }); + + table.push( + ["Best Block", status.bestNumber], + ["Best Finalized Block", status.bestFinalizedNumber], + ["Era", eraInfo.era], + ["Session", `${eraInfo.currentSession}/${eraInfo.sessionsPerEra}`] + ); + console.log("Chain status:"); + console.log(table.toString()); +} diff --git a/scripts/cc-cli/src/utils/status.ts b/scripts/cc-cli/src/utils/validatorStatus.ts similarity index 85% rename from scripts/cc-cli/src/utils/status.ts rename to scripts/cc-cli/src/utils/validatorStatus.ts index 995dd6090b..5f502297ad 100644 --- a/scripts/cc-cli/src/utils/status.ts +++ b/scripts/cc-cli/src/utils/validatorStatus.ts @@ -1,6 +1,7 @@ import { ApiPromise, BN } from "creditcoin-js"; import { readAmount, readAmountFromHex, toCTCString } from "./balance"; import { timeTillEra } from "./era"; +import Table from "cli-table3"; function formatDaysHoursMinutes(ms: number) { const days = Math.floor(ms / (24 * 60 * 60 * 1000)); @@ -19,7 +20,7 @@ function formatDaysHoursMinutes(ms: number) { return `${daysString}${hoursString}${minutesString}${secString}`; } -export async function getStatus(address: string, api: ApiPromise) { +export async function getValidatorStatus(address: string, api: ApiPromise) { const res = await api.derive.staking.account(address); const totalStaked = readAmount(res.stakingLedger.total.toString()); const bonded = totalStaked.gt(new BN(0)); @@ -94,23 +95,22 @@ export async function getStatus(address: string, api: ApiPromise) { } export async function printValidatorStatus(status: Status, api: ApiPromise) { - console.log("Bonded: ", status.bonded); - if (status.stash) console.log("Stash: ", status.stash); - console.log("Controller: ", status.controller); - console.log("Validating: ", status.validating); - console.log("Waiting: ", status.waiting); - console.log("Active: ", status.active); - - console.log("Can withdraw: ", status.canWithdraw); + const table = new Table({ + head: ["Status"], + }); + + table.push(["Bonded", status.bonded ? "Yes" : "No"]); + table.push(["Stash", status.stash ? status.stash : "None"]); + table.push(["Controller", status.controller]); + table.push(["Validating", status.validating ? "Yes" : "No"]); + table.push(["Waiting", status.waiting ? "Yes" : "No"]); + table.push(["Active", status.active ? "Yes" : "No"]); + table.push(["Can withdraw", status.canWithdraw ? "Yes" : "No"]); if (status.canWithdraw) { - console.log("Unlocked chunks: "); status.readyForWithdraw.forEach((chunk) => { - console.log( - ` ${toCTCString(chunk.value)} unlocked since era ${chunk.era}` - ); + table.push([`Unlocked since era ${chunk.era}`, toCTCString(chunk.value)]); }); } - let nextUnlocking = "None"; if (status.nextUnbondingAmount && status.nextUnbondingAmount.eq(new BN(0))) { nextUnlocking = "None"; @@ -121,7 +121,9 @@ export async function printValidatorStatus(status: Status, api: ApiPromise) { nextUnbondingDate.toNumber() )}`; } - console.log(`Next unbonding chunk: ${nextUnlocking}`); + table.push(["Next unlocking", nextUnlocking]); + + console.log(table.toString()); } export function requireStatus(