-
Notifications
You must be signed in to change notification settings - Fork 3
Enhances staking info and validator management #269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhances staking info and validator management #269
Conversation
- Show current epoch with validators, weight, slashed - Show previous epoch with inflation, claimed, unclaimed, slashed - Add --epoch option to query specific epoch data - Clean text output instead of JSON - Update docs with new output format
- Add `staking validators` command showing validator set table with: - Moniker, address, self stake, delegated stake - Pending deposits/withdrawals with amounts - Weight percentage (voting power) - Status (active, quarantined, banned, primed, pending) - Owner/operator role indicators - Add `staking validator-history` command showing: - Slash events (idleness penalties) with percentage - Reward events (ValidatorPrime) with validator/delegator rewards - Timestamps, epochs, and block numbers - Summary with totals - Update staking commands to use positional args (backwards compatible): - `validator-info 0x...` instead of `--validator 0x...` - Same for deposit, exit, claim, prime, delegator commands - Add slashed data to epoch-info output
Only show truly pending deposits (epoch + 2 > current) and withdrawals (epoch + 7 > current) instead of all historical ones. Also add quarantined-validators and banned-validators commands to docs.
WalkthroughThis PR updates staking CLI UX: adds Changes
Sequence DiagramsequenceDiagram
actor CLI as CLI User
participant Cmd as CLI Command
participant Action as ValidatorHistoryAction
participant Client as PublicClient
participant Contracts as Staking/Slashing Contracts
participant Table as CLI Table Renderer
CLI->>Cmd: run `validator-history [validator]`
Cmd->>Action: execute(options)
Action->>Action: resolve network/config & validate validator
Action->>Client: create public client
Action->>Contracts: resolve staking & slashing contract addresses
par Fetch events
Action->>Contracts: fetch slash events for validator
Action->>Contracts: fetch reward events (all)
end
Action->>Action: filter reward events for validator
Action->>Action: collect unique blockNumbers
Action->>Client: batch fetch block timestamps
Client-->>Action: return timestamps
Action->>Action: attach timestamps, convert logs β typed events
Action->>Action: sort events (desc), apply limit, compute totals
Action->>Table: format rows (Time, Epoch, Type, Details, TxId/Block)
Table-->>CLI: display table
Action-->>CLI: print summary (counts, totals, hint if truncated)
Estimated code review effortπ― 4 (Complex) | β±οΈ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touchesβ Failed checks (1 warning)
β Passed checks (2 passed)
β¨ Finishing touches
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (1)
README.md (1)
351-353: Minor inconsistency: Example uses old option syntax.Line 312 shows the updated positional argument syntax
validator-info [validator], but this example still uses--validator 0x.... Consider updating for consistency:# Check validator info - genlayer staking validator-info --validator 0x... + genlayer staking validator-info 0x...
π§Ή Nitpick comments (6)
src/commands/staking/stakingInfo.ts (2)
214-217: Consider validating the epoch parameter.If a user passes an invalid string (e.g.,
--epoch abc),BigInt(options.epoch)will throw an unhandled exception. Consider adding validation:// If specific epoch requested, show just that epoch's data if (options.epoch !== undefined) { + const epochNum = (() => { + try { + const n = BigInt(options.epoch); + if (n < 0n) throw new Error("Epoch must be non-negative"); + return n; + } catch { + this.failSpinner(`Invalid epoch number: ${options.epoch}`); + return null; + } + })(); + if (epochNum === null) return; - const epochNum = BigInt(options.epoch); const epochData = await client.getEpochData(epochNum);
444-454: Hardcoded weight formula constants may drift from contract.The weight calculation replicates the contract formula with hardcoded
ALPHA = 0.6andBETA = 0.5. If these change in the contract, this display will show incorrect weights.Consider either:
- Adding a comment noting where these values come from and when they should be updated
- Fetching these from the contract if exposed
+ // Weight formula mirrors staking contract parameters. + // If contract changes ALPHA/BETA, update here accordingly. + // See: contracts/Staking.sol or equivalent const ALPHA = 0.6; const BETA = 0.5;src/commands/staking/index.ts (4)
13-13: Use@/*import alias for the new import (per repo guidelines).
import {ValidatorHistoryAction, ValidatorHistoryOptions} from "./validatorHistory";should follow the@/*alias convention (and ideally this file should be migrated consistently in a follow-up).
49-64: Avoidconsole.error+process.exit(1)in action handlers; DRY the repeated βrequired validatorβ logic.This pattern is repeated many times and makes testing/error handling harder than necessary. Prefer Commanderβs
command.error(...)(or throw) and extract a small helper to resolve/validate positional-vs-option args.Example pattern (apply similarly across commands):
- .action(async (validatorArg: string | undefined, options: ValidatorDepositOptions) => { - const validator = validatorArg || options.validator; - if (!validator) { - console.error("Error: validator address is required"); - process.exit(1); - } + .action(async (validatorArg: string | undefined, options: ValidatorDepositOptions, command: Command) => { + const validator = validatorArg ?? options.validator; + if (!validator) command.error("Error: validator address is required", {exitCode: 1}); const action = new ValidatorDepositAction(); await action.execute({...options, validator}); });Also consider adjusting the
optionstypes in these handlers: many of the*Optionsinterfaces havevalidator: stringrequired, but with positional args + deprecated--validator, the parsed Commanderoptions.validatoris effectively optional at the handler boundary.Also applies to: 66-83, 84-118, 119-137, 138-163, 166-183, 185-202, 204-221, 238-255
259-266: Parse/validate--epochat the Commander layer (better UX + fewer downstream checks).Consider an option parser (or explicit validation) so
epoch-info --epoch foofails fast with a clear message (and so negative/out-of-range values are rejected consistently).
313-328:validator-historycommand registration looks good; consider a small help/validation polish.Given the action refuses localnet (no
eth_getLogs), you may want to mention that constraint in the command description or option help text; also consider validating--from-block/--limitas integers in the CLI layer for quicker feedback.
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
β Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
π Files selected for processing (6)
README.md(3 hunks)docs/validator-guide.md(1 hunks)package.json(1 hunks)src/commands/staking/index.ts(4 hunks)src/commands/staking/stakingInfo.ts(4 hunks)src/commands/staking/validatorHistory.ts(1 hunks)
π§° Additional context used
π Path-based instructions (3)
src/commands/**/*.ts
π CodeRabbit inference engine (CLAUDE.md)
All CLI action classes must extend
BaseActionfromsrc/lib/actions/BaseAction.tswhich provides GenLayer client initialization, keystore management, spinner/logging utilities, and user prompts
Files:
src/commands/staking/stakingInfo.tssrc/commands/staking/validatorHistory.tssrc/commands/staking/index.ts
**/*.{ts,tsx,js,jsx}
π CodeRabbit inference engine (CLAUDE.md)
Use
@/*path alias to reference./src/*and@@/tests/*path alias to reference./tests/*in imports
Files:
src/commands/staking/stakingInfo.tssrc/commands/staking/validatorHistory.tssrc/commands/staking/index.ts
src/commands/*/index.ts
π CodeRabbit inference engine (CLAUDE.md)
Commands must be organized in
src/commands/<domain>/index.tswith each file exporting aninitialize*Commands(program)function
Files:
src/commands/staking/index.ts
π§ Learnings (7)
π Learning: 2025-07-10T23:50:34.628Z
Learnt from: epsjunior
Repo: genlayerlabs/genlayer-cli PR: 239
File: package.json:60-66
Timestamp: 2025-07-10T23:50:34.628Z
Learning: In the genlayer-cli project, dotenv is used with manual parsing via dotenv.parse() rather than automatic loading via dotenv.config(), so warnings about implicit .env.local auto-loading changes in dotenv v17 are not applicable to this project.
Applied to files:
package.json
π Learning: 2025-12-03T23:03:32.323Z
Learnt from: CR
Repo: genlayerlabs/genlayer-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T23:03:32.323Z
Learning: Use `npm install` to install dependencies, `npm run dev` for watch mode development build using esbuild, `npm run build` for production build, and `node dist/index.js` to run CLI from source
Applied to files:
package.json
π Learning: 2025-09-03T13:20:22.582Z
Learnt from: epsjunior
Repo: genlayerlabs/genlayer-cli PR: 253
File: tests/actions/code.test.ts:78-84
Timestamp: 2025-09-03T13:20:22.582Z
Learning: In genlayer-cli, the CLI framework handles unhandled promise rejections globally, so errors outside try/catch blocks are still displayed to users appropriately.
Applied to files:
package.json
π Learning: 2025-12-03T23:03:32.323Z
Learnt from: CR
Repo: genlayerlabs/genlayer-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T23:03:32.323Z
Learning: Applies to src/commands/**/*.ts : All CLI action classes must extend `BaseAction` from `src/lib/actions/BaseAction.ts` which provides GenLayer client initialization, keystore management, spinner/logging utilities, and user prompts
Applied to files:
src/commands/staking/stakingInfo.tssrc/commands/staking/index.ts
π Learning: 2025-12-03T23:03:32.323Z
Learnt from: CR
Repo: genlayerlabs/genlayer-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T23:03:32.323Z
Learning: When adding commands, create action class extending `BaseAction` in `src/commands/<domain>/<action>.ts`, export action options interface, register in domain's `index.ts` via Commander, and add tests in `tests/commands/<domain>.test.ts` and `tests/actions/<action>.test.ts`
Applied to files:
src/commands/staking/index.ts
π Learning: 2025-12-03T23:03:32.323Z
Learnt from: CR
Repo: genlayerlabs/genlayer-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T23:03:32.323Z
Learning: Applies to src/commands/*/index.ts : Commands must be organized in `src/commands/<domain>/index.ts` with each file exporting an `initialize*Commands(program)` function
Applied to files:
src/commands/staking/index.ts
π Learning: 2025-12-03T23:03:32.323Z
Learnt from: CR
Repo: genlayerlabs/genlayer-cli PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T23:03:32.323Z
Learning: Applies to src/index.ts : Main entry point is `src/index.ts` which initializes Commander program and registers all command groups
Applied to files:
src/commands/staking/index.ts
𧬠Code graph analysis (3)
src/commands/staking/stakingInfo.ts (1)
src/commands/staking/StakingAction.ts (2)
StakingConfig(12-17)formatAmount(145-147)
src/commands/staking/validatorHistory.ts (1)
src/commands/staking/StakingAction.ts (2)
StakingConfig(12-17)StakingAction(19-196)
src/commands/staking/index.ts (9)
src/commands/staking/validatorDeposit.ts (2)
ValidatorDepositOptions(5-8)ValidatorDepositAction(10-48)src/commands/staking/validatorClaim.ts (2)
ValidatorClaimOptions(5-7)ValidatorClaimAction(9-43)src/commands/staking/setOperator.ts (2)
SetOperatorOptions(5-8)SetOperatorAction(10-46)src/commands/staking/setIdentity.ts (2)
SetIdentityOptions(6-17)SetIdentityAction(19-78)src/commands/staking/delegatorJoin.ts (2)
DelegatorJoinOptions(5-8)DelegatorJoinAction(10-44)src/commands/staking/delegatorExit.ts (2)
DelegatorExitOptions(4-7)DelegatorExitAction(9-56)src/commands/staking/delegatorClaim.ts (2)
DelegatorClaimOptions(4-7)DelegatorClaimAction(9-41)src/commands/staking/stakingInfo.ts (2)
StakingInfoOptions(10-12)StakingInfoAction(14-566)src/commands/staking/validatorHistory.ts (2)
ValidatorHistoryOptions(30-34)ValidatorHistoryAction(56-259)
π Additional comments (14)
src/commands/staking/stakingInfo.ts (4)
2-4: LGTM - Imports are appropriate for the new functionality.
449-454: LGTM - Precision is adequate for display percentages.Using floating-point for the weight calculation is acceptable since it's only for display purposes (showing relative percentages) rather than financial calculations.
501-515: LGTM - Pending filter logic is consistent with other methods.The filtering of truly pending deposits/withdrawals using
ACTIVATION_DELAY_EPOCHSandUNBONDING_PERIOD_EPOCHSconstants is consistent with the same logic ingetValidatorInfoandgetStakeInfo.
351-565: LGTM - Well-structured validator listing implementation.The implementation follows good practices:
- Parallel data fetching for performance
- Batch processing to avoid rate limiting
- Graceful handling of missing signer address
- Consistent error handling pattern
docs/validator-guide.md (1)
91-113: LGTM - Documentation accurately reflects the new epoch-info output.The updated example clearly shows the enhanced human-readable format with current/previous epoch details and staking requirements, matching the implementation in
stakingInfo.ts.src/commands/staking/validatorHistory.ts (6)
77-96: LGTM - Good early validation and fallback handling.The method properly:
- Checks for unsupported localnet early
- Falls back to signer address when validator not specified
- Validates the address is actually a validator before expensive log fetching
145-156: LGTM - Efficient batch fetching of block timestamps.Batching with
Promise.allis appropriate. Consider that if a single block fetch fails, the entire batch will fail. For robustness, you might wantPromise.allSettled, but this is likely fine for the typical case.
158-175: LGTM - Event transformation is correct.The type assertions for
log.argsare necessary due to viem's generic types. The fallback toDate(0)for missing timestamps is a safe default.
190-254: LGTM - Clear and informative display output.The output handling is well done:
- Graceful empty state handling
- Informative table with colored status indicators
- Summary shows totals from all events (not just limited display)
- Clear indication when results are truncated
61-75: [Rewritten review comment]
[Classification tag]
8-28: These event ABIs are hardcoded; verify they match the deployed staking and slashing contracts before deployment.The
SLASH_EVENT_ABIandREWARD_EVENT_ABIare used bypublicClient.getLogs()to fetch and parse events from deployed contracts. If these ABIs become out of sync with the actual contract implementations (e.g., after a contract upgrade or if field definitions change), event parsing will fail or produce incorrect results. Consider establishing a process to verify ABI compatibility against deployed contracts during QA and before any contract upgrades.package.json (1)
63-63: LGTM - Dependencies align with new features.The cli-table3 addition supports the new tabular validator display (used in
stakingInfo.tsandvalidatorHistory.ts), and the genlayer-js bump to ^0.18.9 includes necessary API additions for the staking commands. cli-table3@^0.6.5 is the latest available version on npm.src/commands/staking/index.ts (2)
301-312: Newstaking validatorscommand wiring looks clean and consistent with existing info commands.Nice addition; the options surface matches the other staking-info style commands.
119-137: No typo found. ThesetOperator.tsfile correctly usesabi.VALIDATOR_WALLET_ABI(all uppercase) on line 26, and theSetOperatorActionclass is properly implemented and imported.Likely an incorrect or invalid review comment.
| // Fetch reward events (not indexed, need to filter client-side) | ||
| const rewardLogs = await publicClient.getLogs({ | ||
| address: stakingAddress, | ||
| event: REWARD_EVENT_ABI, | ||
| fromBlock, | ||
| toBlock: "latest", | ||
| }); | ||
|
|
||
| // Filter rewards to this validator | ||
| const filteredRewardLogs = rewardLogs.filter( | ||
| log => (log.args as any).validator?.toLowerCase() === validatorAddress.toLowerCase() | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Performance concern: Unbounded reward log fetching.
Fetching all ValidatorPrime events from block 0 (or fromBlock) with client-side filtering could be expensive on a chain with many epochs. Since the validator field isn't indexed, all reward events must be downloaded.
Consider:
- Using a more recent default
fromBlock(e.g., last N epochs based on epoch duration) - Documenting that
--from-blockshould be used for older validators - Adding a warning when fetching from genesis
+ // Fetch reward events (not indexed, need to filter client-side)
+ // Note: This fetches ALL reward events which could be slow on long chains
const rewardLogs = await publicClient.getLogs({Committable suggestion skipped: line range outside the PR's diff.
π€ Prompt for AI Agents
In src/commands/staking/validatorHistory.ts around lines 126 to 137, the code
unconditionally fetches all reward logs (potentially from genesis) then filters
client-side which can be extremely expensive; change the logic to use a safe
recent default fromBlock (e.g. compute a block window covering last N epochs
based on epoch duration or use now - X blocks) when none is provided, log a
warning if the user is about to fetch from genesis, and update the CLI
help/documentation to recommend using --from-block for long-lived validators;
implement the default-fromBlock calculation, emit a single warning when
fromBlock <= genesis or not provided, and ensure the --from-block flag remains
honored for older validators.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
π§Ή Nitpick comments (1)
tests/actions/staking.test.ts (1)
212-220: Use a fixed timestamp for test determinism.The mock uses
Date.now()to calculate the start timestamp, which makes the test non-deterministic. Tests should use fixed, known values for reproducibility and easier debugging.Apply this diff to use a fixed timestamp:
mockClient.getEpochData.mockResolvedValue({ - start: BigInt(Math.floor(Date.now() / 1000) - 3600), + start: 1704063600n, // Fixed timestamp: 2024-01-01T00:00:00Z - 3600 end: 0n, vcount: 5n, weight: 100000n, inflation: 1000n * BigInt(1e18), claimed: 500n * BigInt(1e18), slashed: 0n, });
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (1)
tests/actions/staking.test.ts(3 hunks)
π§° Additional context used
π Path-based instructions (1)
**/*.{ts,tsx,js,jsx}
π CodeRabbit inference engine (CLAUDE.md)
Use
@/*path alias to reference./src/*and@@/tests/*path alias to reference./tests/*in imports
Files:
tests/actions/staking.test.ts
π Additional comments (2)
tests/actions/staking.test.ts (2)
67-69: LGTM!The mock extensions for
getEpochDataandformatStakingAmountproperly support the new epoch-related functionality introduced in this PR.
266-266: The test expectation is correct and accurately matches the implementation. Line 243 ofsrc/commands/staking/stakingInfo.tscallsthis.succeedSpinner("Epoch info")with only a single argument, which is exactly what the test expects on line 266. While other similar methods likegetValidatorInfoandlistActiveValidatorsuse the pattern "{X} retrieved" with an additional data parameter, thegetEpochInfomethod intentionally uses a different pattern. This is not an error in the test.
Improves the staking command suite with enhanced info displays and validator management features.
The validator table includes details like self-stake, delegation stake, pending deposits/withdrawals, weight, and status.
The validator history command fetches and displays slash and reward events for a specified validator, useful for monitoring performance.
The epoch info display now includes both the current and previous epochs, providing a more comprehensive view of the staking status. Also adds specific epoch querying.
Summary by CodeRabbit
New Features
validatorstable view andvalidator-historyreport; new listings for quarantined and banned validators.epoch-infonow shows richer, human-readable current/next/previous epoch metrics, inflation, and stake details.Documentation
Tests
βοΈ Tip: You can customize this high-level summary in your review settings.