Skip to content

Conversation

@fadeev
Copy link
Member

@fadeev fadeev commented Sep 26, 2025

Validator List

yarn -s zetachain staking validators list 
✔ Fetched 31 validators of 31
┌───────────────────────────┬────────────────────────────────────────────────────┬────────┬────────┬──────────────┬──────┐
│ Moniker                   │ Operator                                           │ Status │ Jailed │ Voting Power │ Comm │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│ Just another validator    │ 0x0736374C4532b3b13684913e138525729d78eC8f         │ Bonded │ false  │ 32053.53     │ 5%   │
│ with good service.        │ zetavaloper1qumrwnz9x2emzd5yjylp8pf9w2wh3my0gag27y │        │        │              │      │
│ Discord: liver23          │                                                    │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│                           │ 0x0C73b4676c381e9DaddE7d9227671Bc308D28960         │ Bonded │ false  │ 115625.58    │ 10%  │
│                           │ zetavaloper1p3emgemv8q0fmtw70kfzwecmcvyd9ztqlzudwn │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│                           │ 0x26E63720b989865359D55110291a356918E62f0a         │ Bonded │ false  │ 786941.79    │ 5%   │
│                           │ zetavaloper1ymnrwg9e3xr9xkw42ygzjx34dyvwvtc24ct0t5 │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│ Distributed multi-chain   │ 0x359aD9Df0d25255Ef0594C8165C6C1a697a603D0         │ Bonded │ false  │ 98955.16     │ 10%  │
│ acceleration layer.       │ zetavaloper1xkddnhcdy5j4auzefjqkt3kp56t6vq7sm5xlga │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│                           │ 0x386d090B1Fb423505804eF6e950fb6840EFdCf90         │ Bonded │ false  │ 465169.42    │ 5%   │
│                           │ zetavaloper18pksjzclks34qkqyaahf2rakss80mnuskuxz4d │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│                           │ 0x3997bA285160BD6A731Ab136a8F95820779A0F17         │ Bonded │ false  │ 5001.31      │ 10%  │
│                           │ zetavaloper18xtm52z3vz7k5uc6kym2372cypme5rchhfsdy9 │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│ DSRV is an integrated     │ 0x3A723D1875fdc29AB383a3fd8a844D2f04Ec317b         │ Bonded │ false  │ 98213.62     │ 10%  │
│ blockchain solutions      │ zetavaloper18fer6xr4lhpf4vur507c4pzd9uzwcvtmxyyz9t │        │        │              │      │
│ company with the mission  │                                                    │        │        │              │      │
│ of enriching the crypto   │                                                    │        │        │              │      │
│ ecosystem via stronger    │                                                    │        │        │              │      │
│ connectivity. We strive   │                                                    │        │        │              │      │
│ to be your gateway to a   │                                                    │        │        │              │      │
│ suite of                  │                                                    │        │        │              │      │
│ all-comprehensive         │                                                    │        │        │              │      │
│ blockchain services.      │                                                    │        │        │              │      │
│ Everything distributed,   │                                                    │        │        │              │      │
│ served complete.          │                                                    │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│                           │ 0x420029269e56b9cf1B1a0a5C87bFf3278aED2e3d         │ Bonded │ false  │ 110185.39    │ 10%  │
│                           │ zetavaloper1ggqzjf5726uu7xc6pfwg00lny79w6t3a4unarz │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤
│                           │ 0x44551Ff209e94006499c0F643cA9a1bf33B294A9         │ Bonded │ false  │ 193242.92    │ 10%  │
│                           │ zetavaloper1g323lusfa9qqvjvupajre2dphuem999fehqn2v │        │        │              │      │
├───────────────────────────┼────────────────────────────────────────────────────┼────────┼────────┼──────────────┼──────┤

Delegate

yarn -s zetachain staking delegate \
  --validator zetavaloper17d6ttmqffr5pwt9fd7uuj8px27quv4nljf3s8j \
  --amount 1 \
  --private-key $PRIVATE_KEY

Summary by CodeRabbit

  • New Features

    • Introduced staking command group with subcommands: validators list, delegations list/show, delegate, undelegate, and redelegate.
    • Supports human-readable tables and JSON output, with pagination/batching for large datasets.
    • Interactive confirmations with optional --yes flag; displays transaction hashes on success.
    • Automatic defaults for chain ID and RPC when not provided.
  • Bug Fixes

    • Corrected a JSON artifact formatting issue (no behavioral impact).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

📝 Walkthrough

Walkthrough

Adds a new staking CLI surface with root command and subcommands (validators, delegations, delegate, undelegate, redelegate). Registers the staking command in the main program and exports it publicly. Introduces staking precompile ABI, constants, schemas, and helper API tweaks, plus multicall JSON fix.

Changes

Cohort / File(s) Summary
CLI surface integration
packages/commands/src/index.ts, packages/commands/src/program.ts
Exposes staking exports and registers stakingCommand with the main CLI program.
Staking root and ABI
packages/commands/src/staking/index.ts, packages/commands/src/staking/staking.json
Adds stakingCommand parent with subcommands; introduces staking precompile ABI artifact.
Staking tx commands
packages/commands/src/staking/delegate.ts, packages/commands/src/staking/undelegate.ts, packages/commands/src/staking/redelegate.ts
Adds transactional commands to delegate, undelegate, and redelegate via staking precompile; validates inputs, confirms, encodes ABI, sends tx, outputs receipt.
Delegations queries
packages/commands/src/staking/delegations/index.ts, packages/commands/src/staking/delegations/list.ts, packages/commands/src/staking/delegations/show.ts
Adds delegations parent plus list (multicall-based aggregation with pagination/fallback) and show (single delegation) commands with JSON/pretty output.
Validators queries
packages/commands/src/staking/validators/index.ts, packages/commands/src/staking/validators/list.ts
Adds validators parent and list command with status filter, pagination, formatting, and JSON output.
Constants and schemas
src/constants/addresses.ts, src/schemas/commands/validators.ts
Adds STAKING_PRECOMPILE address constant; introduces validators list options schema and type.
Utils updates
utils/zetachain.command.helpers.ts, utils/multicall3.json
Exports helper types, narrows helper function input types, adds default chain derivation; fixes JSON bracket formatting in Multicall3 artifact.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant CLI as CLI (commander)
  participant Helpers as Helpers (setup/confirm)
  participant Ethers as Ethers.js
  participant Chain as Staking Precompile

  rect rgb(238,245,255)
    note right of CLI: New staking tx subcommands
    User->>CLI: staking [delegate|undelegate|redelegate] --opts
    CLI->>Helpers: validate options, setup tx (rpc, signer)
    Helpers-->>CLI: signer, provider, address
    CLI->>User: print intent & details
    CLI->>Helpers: confirm (--yes or prompt)
    alt confirmed
      CLI->>Ethers: encode ABI call data
      Ethers->>Chain: sendTransaction(to=STAKING_PRECOMPILE, data/value)
      Chain-->>Ethers: receipt
      Ethers-->>CLI: tx hash / receipt
      CLI-->>User: output tx hash
    else cancelled
      CLI-->>User: exit without sending
    end
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant CLI as CLI (validators/delegations)
  participant Ethers as Provider+Contracts
  participant Chain as Staking Precompile
  participant MC as Multicall3

  rect rgb(245,255,245)
    note right of CLI: New query subcommands
    User->>CLI: staking validators list --status/--json
    CLI->>Ethers: call validators(...) with pagination
    loop pages
      Ethers->>Chain: validators(PageRequest, status)
      Chain-->>Ethers: page of validators + nextKey
    end
    CLI-->>User: JSON or table
  end

  rect rgb(255,248,240)
    User->>CLI: staking delegations list --address
    CLI->>Ethers: fetch validator set (statuses, pages)
    CLI->>MC: try aggregate delegation(addr, each validator) batched
    alt multicall success
      MC-->>CLI: results decoded
    else fallback
      CLI->>Chain: delegation(addr, validator) per item (bounded)
      Chain-->>CLI: results
    end
    CLI-->>User: JSON or table
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • feat: Zetachain call command #338 — Also modifies CLI surface by adding a new command export and registering it with toolkitCommand, overlapping with index/program integration patterns.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “feat: staking commands” succinctly describes the primary addition of staking-related CLI commands, matching the extensive set of staking features introduced without unnecessary detail.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staking-commands

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the feat label Sep 26, 2025
@fadeev fadeev linked an issue Sep 26, 2025 that may be closed by this pull request
@fadeev fadeev linked an issue Sep 26, 2025 that may be closed by this pull request
@fadeev fadeev marked this pull request as ready for review October 2, 2025 16:57
@fadeev fadeev requested review from a team as code owners October 2, 2025 16:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (5)
packages/commands/src/staking/delegate.ts (2)

21-31: Tighten input validation for amount and validator.

Prevent invalid/negative values and guide users on address formats.

Apply this diff to the schema:

-    amount: z.string(),
+    amount: z
+      .string()
+      .refine((v) => {
+        try {
+          return ethers.parseEther(v) > 0n;
+        } catch {
+          return false;
+        }
+      }, "Amount must be a positive decimal number"),
@@
-    validator: z.string(),
+    validator: z
+      .string()
+      .refine(
+        (v) =>
+          /^0x[0-9a-fA-F]{40}$/.test(v) || v.startsWith("zetavaloper1"),
+        "Validator must be 0x… or zetavaloper…"
+      ),

90-92: Clarify flag help: accept 0x or bech32.

Update help text so users know both formats are supported.

-      "Validator operator address (zetavaloper...)"
+      "Validator operator address (0x… or zetavaloper…)"
packages/commands/src/staking/validators/list.ts (3)

1-7: Import Buffer explicitly to avoid ESM/bundler issues.

Buffer is global in Node, but explicit import improves portability.

 import { bech32 } from "bech32";
 import chalk from "chalk";
 import { Command, Option } from "commander";
 import { ethers } from "ethers";
 import ora from "ora";
 import { getBorderCharacters, table } from "table";
+import { Buffer } from "buffer";

104-110: Hoist static statusMap to module scope.

Avoid re-allocating per row.

-    const statusMap: Record<number, string> = {
-      0: "Unspecified",
-      1: "Unbonded",
-      2: "Unbonding",
-      3: "Bonded",
-    };
+    // at module scope:
+    // const statusMap: Record<number, string> = { 0: "Unspecified", 1: "Unbonded", 2: "Unbonding", 3: "Bonded" };

336-338: Unify schema validation UX with existing helper.

Use validateAndParseSchema for consistent error formatting and exit behavior across commands.

-    const options = validatorsListOptionsSchema.parse(rawOptions);
+    import { validateAndParseSchema } from "../../../../../utils";
+    const options = validateAndParseSchema(rawOptions, validatorsListOptionsSchema, { exitOnError: true });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 78087ef and aba5b11.

⛔ Files ignored due to path filters (23)
  • typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/token/ERC20/utils/SafeERC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/utils/Address__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@zetachain/protocol-contracts/contracts/evm/ERC20Custody__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@zetachain/protocol-contracts/contracts/evm/GatewayEVM__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@zetachain/protocol-contracts/contracts/evm/ZetaConnectorNative__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@zetachain/protocol-contracts/contracts/evm/ZetaConnectorNonNative__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/EthZetaMock.sol/ZetaEthMock__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/SwapHelpers.sol/SwapLibrary__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/TestZRC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/shared/MockZRC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/EVMSetup.t.sol/EVMSetup__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/FoundrySetup.t.sol/FoundrySetup__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/TokenSetup.t.sol/TokenSetup__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/UniswapV2SetupLib.sol/UniswapV2SetupLib__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/UniswapV3SetupLib.sol/UniswapV3SetupLib__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/ZetaSetup.t.sol/ZetaSetup__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/mock/ERC20Mock__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/mockGateway/NodeLogicMock__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/mockGateway/WrapGatewayEVM__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/testing/mockGateway/WrapGatewayZEVM__factory.ts is excluded by !typechain-types/**
📒 Files selected for processing (16)
  • packages/commands/src/index.ts (1 hunks)
  • packages/commands/src/program.ts (2 hunks)
  • packages/commands/src/staking/delegate.ts (1 hunks)
  • packages/commands/src/staking/delegations/index.ts (1 hunks)
  • packages/commands/src/staking/delegations/list.ts (1 hunks)
  • packages/commands/src/staking/delegations/show.ts (1 hunks)
  • packages/commands/src/staking/index.ts (1 hunks)
  • packages/commands/src/staking/redelegate.ts (1 hunks)
  • packages/commands/src/staking/staking.json (1 hunks)
  • packages/commands/src/staking/undelegate.ts (1 hunks)
  • packages/commands/src/staking/validators/index.ts (1 hunks)
  • packages/commands/src/staking/validators/list.ts (1 hunks)
  • src/constants/addresses.ts (1 hunks)
  • src/schemas/commands/validators.ts (1 hunks)
  • utils/multicall3.json (1 hunks)
  • utils/zetachain.command.helpers.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: fadeev
PR: zeta-chain/toolkit#346
File: packages/commands/src/ton/depositAndCall.ts:0-0
Timestamp: 2025-06-13T15:33:54.781Z
Learning: fadeev prefers responses in English.
🧬 Code graph analysis (11)
packages/commands/src/staking/delegations/show.ts (2)
src/constants/addresses.ts (1)
  • STAKING_PRECOMPILE (2-2)
src/constants/api.ts (1)
  • DEFAULT_EVM_RPC_URL (3-4)
packages/commands/src/staking/delegations/index.ts (2)
packages/commands/src/staking/delegations/list.ts (1)
  • listCommand (412-428)
packages/commands/src/staking/delegations/show.ts (1)
  • showCommand (57-84)
packages/commands/src/staking/index.ts (5)
packages/commands/src/staking/validators/index.ts (1)
  • validatorsCommand (5-8)
packages/commands/src/staking/delegate.ts (1)
  • delegateCommand (83-85)
packages/commands/src/staking/undelegate.ts (1)
  • undelegateCommand (82-84)
packages/commands/src/staking/redelegate.ts (1)
  • redelegateCommand (85-87)
packages/commands/src/staking/delegations/index.ts (1)
  • delegationsCommand (6-10)
packages/commands/src/staking/delegations/list.ts (6)
types/shared.schema.ts (2)
  • evmAddressSchema (9-11)
  • rpcOrChainIdRefineRule (133-138)
utils/validateAndParseSchema.ts (1)
  • validateAndParseSchema (28-59)
utils/chains.ts (1)
  • getRpcUrl (3-15)
src/constants/addresses.ts (2)
  • STAKING_PRECOMPILE (2-2)
  • MULTICALL_ADDRESS (1-1)
types/balances.types.ts (1)
  • MULTICALL3_ABI (54-75)
src/constants/api.ts (1)
  • DEFAULT_EVM_RPC_URL (3-4)
packages/commands/src/staking/undelegate.ts (5)
types/shared.schema.ts (1)
  • namePkRefineRule (69-74)
utils/zetachain.command.helpers.ts (4)
  • setupZetachainTransaction (64-100)
  • SetupTxOptionsSubset (58-61)
  • confirmZetachainTransaction (102-136)
  • ConfirmTxOptionsSubset (62-62)
src/constants/addresses.ts (1)
  • STAKING_PRECOMPILE (2-2)
utils/handleError.ts (1)
  • handleError (31-45)
utils/validateAndParseSchema.ts (1)
  • validateAndParseSchema (28-59)
packages/commands/src/staking/validators/list.ts (4)
packages/tasks/src/account.ts (1)
  • main (121-169)
src/constants/addresses.ts (1)
  • STAKING_PRECOMPILE (2-2)
src/constants/api.ts (1)
  • DEFAULT_EVM_RPC_URL (3-4)
src/schemas/commands/validators.ts (1)
  • validatorsListOptionsSchema (3-7)
packages/commands/src/program.ts (1)
packages/commands/src/staking/index.ts (1)
  • stakingCommand (9-16)
utils/zetachain.command.helpers.ts (1)
utils/chains.ts (1)
  • getRpcUrl (3-15)
packages/commands/src/staking/delegate.ts (5)
types/shared.schema.ts (1)
  • namePkRefineRule (69-74)
utils/zetachain.command.helpers.ts (4)
  • setupZetachainTransaction (64-100)
  • SetupTxOptionsSubset (58-61)
  • confirmZetachainTransaction (102-136)
  • ConfirmTxOptionsSubset (62-62)
src/constants/addresses.ts (1)
  • STAKING_PRECOMPILE (2-2)
utils/handleError.ts (1)
  • handleError (31-45)
utils/validateAndParseSchema.ts (1)
  • validateAndParseSchema (28-59)
packages/commands/src/staking/validators/index.ts (1)
packages/commands/src/staking/validators/list.ts (1)
  • listCommand (324-339)
packages/commands/src/staking/redelegate.ts (5)
types/shared.schema.ts (1)
  • namePkRefineRule (69-74)
utils/zetachain.command.helpers.ts (4)
  • setupZetachainTransaction (64-100)
  • SetupTxOptionsSubset (58-61)
  • confirmZetachainTransaction (102-136)
  • ConfirmTxOptionsSubset (62-62)
src/constants/addresses.ts (1)
  • STAKING_PRECOMPILE (2-2)
utils/handleError.ts (1)
  • handleError (31-45)
utils/validateAndParseSchema.ts (1)
  • validateAndParseSchema (28-59)
🔇 Additional comments (11)
utils/zetachain.command.helpers.ts (2)

56-62: LGTM! Type exports follow least-privilege pattern.

Exporting BaseZetachainOptions and introducing SetupTxOptionsSubset and ConfirmTxOptionsSubset provides clear type contracts for the narrowed function signatures. This improves type safety by restricting each function to only the options it actually uses.


102-136: LGTM! Signature narrowing is consistent.

The function signature now accepts ConfirmTxOptionsSubset, consistent with the subset pattern applied to setupZetachainTransaction. No behavioral changes.

packages/commands/src/index.ts (1)

7-7: LGTM! Staking module added to public API.

The new export expands the public API surface to include staking commands, consistent with the PR objectives.

src/constants/addresses.ts (1)

2-2: LGTM! Staking precompile address added.

The constant follows the standard pattern for precompile addresses (low address space). Used by staking command modules for transaction encoding.

utils/multicall3.json (1)

38-38: LGTM! JSON formatting corrected.

Trailing formatting issue fixed. No functional changes.

packages/commands/src/program.ts (1)

11-11: LGTM! Staking command registered with toolkit.

The command is imported and registered following the established pattern for other commands. No issues identified.

Also applies to: 29-29

src/schemas/commands/validators.ts (1)

1-10: LGTM! Validators list options schema is well-defined.

The schema provides clear validation for the validators list command options. The required rpc field is reasonable since the command definition (in list.ts) provides a default value via Commander before schema validation.

packages/commands/src/staking/delegations/index.ts (1)

1-11: LGTM! Delegations command structure is standard.

The parent command follows the established pattern for organizing subcommands. The structure is clear and consistent with other command modules.

packages/commands/src/staking/validators/index.ts (1)

1-9: LGTM! Validators command structure is standard.

The parent command follows the same clear pattern as the delegations command. Structure is consistent and well-organized.

packages/commands/src/staking/validators/list.ts (2)

189-279: Robust pagination and status probing — nice work.

Candidate probing + nextKey loop and mixed-shape decoding are solid and resilient.


117-132: No change needed: zetavaloper uses original Bech32
Confirmed that validator-operator (zetavaloper) addresses use the original Bech32 format; the current bech32.encode implementation is correct.

Comment on lines +59 to +63
const data = iface.encodeFunctionData("delegate", [
delegatorAddress,
options.validator,
amountWei,
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Validator address must be normalized (accept bech32 valoper and 0x).

You pass options.validator as-is. CLI examples use zetavaloper… bech32, while the precompile likely expects a 20‑byte EVM address. Normalize input to 0x… (and checksum) before encoding.

Apply this diff in-place to use a normalized address:

-    const data = iface.encodeFunctionData("delegate", [
-      delegatorAddress,
-      options.validator,
-      amountWei,
-    ]);
+    const validatorHex = normalizeValidatorAddress(options.validator);
+    const data = iface.encodeFunctionData("delegate", [
+      delegatorAddress,
+      validatorHex,
+      amountWei,
+    ]);

Add this helper and imports outside the range:

import { bech32 } from "bech32";
import { Buffer } from "buffer";

const normalizeValidatorAddress = (input: string): string => {
  if (/^0x[0-9a-fA-F]{40}$/.test(input)) return ethers.getAddress(input);
  try {
    const { prefix, words } = bech32.decode(input);
    if (prefix !== "zetavaloper") throw new Error("invalid bech32 prefix");
    const bytes = Buffer.from(bech32.fromWords(words));
    if (bytes.length !== 20) throw new Error("expected 20-byte operator address");
    return ethers.getAddress("0x" + bytes.toString("hex"));
  } catch {
    throw new Error(
      "Validator must be a 0x…20-byte address or a zetavaloper… bech32 string"
    );
  }
};
🤖 Prompt for AI Agents
In packages/commands/src/staking/delegate.ts around lines 59 to 63,
options.validator is passed as-is but the precompile expects a 20-byte EVM
address; add a normalize helper and imports and use it when encoding. Add
imports for bech32 and Buffer and implement normalizeValidatorAddress that
accepts either 0x..40hex or zetavaloper bech32, decodes bech32 to 20 bytes,
validates length and prefix, then returns ethers.getAddress(hex) (throwing a
clear error on invalid input). Replace the current use of options.validator in
iface.encodeFunctionData("delegate", [...]) with
normalizeValidatorAddress(options.validator) so a checksummed 0x address is
encoded.

Comment on lines +65 to +69
const tx = await signer.sendTransaction({
data,
to: STAKING_PRECOMPILE,
value: amountWei,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Double-specifying amount (calldata + msg.value) may be wrong for this ABI. Please verify.

You encode amount as a parameter and also send value: amountWei. Depending on the staking precompile ABI, only one may be required.

Run to confirm the delegate signature and mutability:

If inputs do not include an amount (or stateMutability is payable), drop the calldata amount and rely on msg.value; otherwise, keep the calldata amount and set value: 0n.


🏁 Script executed:

#!/bin/bash
# Locate staking.json and inspect the `delegate` function signature.
set -euo pipefail
fd -a 'staking.json' | while read -r f; do
  echo "File: $f"
  jq -r '
    .abi
    | map(select(.type=="function" and .name=="delegate"))
    | .[] | {name, stateMutability, inputs, outputs}
  ' "$f"
done

Length of output: 553


Drop value for delegate transaction
The delegate ABI is nonpayable and already takes amount as a parameter—remove value: amountWei from the transaction to prevent reverts.

🤖 Prompt for AI Agents
In packages/commands/src/staking/delegate.ts around lines 65 to 69, the
transaction is including value: amountWei which causes reverts because the
delegate ABI is nonpayable and already encodes the amount in the calldata;
remove the value field from the signer.sendTransaction call (or set value to 0)
so the transaction doesn't send ETH and leave the amount solely in the encoded
data parameter.

Comment on lines +21 to +33
const provider = new ethers.JsonRpcProvider(opts.rpc);
const contract = new ethers.Contract(
STAKING_PRECOMPILE,
STAKING_ABI,
provider
);
const [shares, balance] = (await contract.delegation(
opts.address,
opts.validator
)) as [bigint, { amount: bigint; denom: string }];

const result = {
address: opts.address,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure hex validator input is converted to bech32 before querying

The CLI advertises --validator accepts hex or bech32, but the call forwards hex straight into contract.delegation. The staking precompile expects a bech32 operator string, so passing hex causes the call to revert. Normalize hex addresses to zetavaloper before invoking the contract (like the list command already does) so both forms work.

+import { bech32 } from "bech32";
...
-    const [shares, balance] = (await contract.delegation(
-      opts.address,
-      opts.validator
-    )) as [bigint, { amount: bigint; denom: string }];
+    const validator =
+      /^0x[0-9a-fA-F]{40}$/.test(opts.validator)
+        ? bech32.encode(
+            "zetavaloper",
+            bech32.toWords(Buffer.from(opts.validator.slice(2), "hex"))
+          )
+        : opts.validator;
+
+    const [shares, balance] = (await contract.delegation(
+      opts.address,
+      validator
+    )) as [bigint, { amount: bigint; denom: string }];
🤖 Prompt for AI Agents
packages/commands/src/staking/delegations/show.ts lines 21-33: the validator
argument may be hex but the staking precompile expects a bech32 operator string,
so normalize the input before calling contract.delegation; detect if
opts.validator is a hex address and convert it to the zetavaloper bech32 form
(reuse the same conversion/helper used in the list command) and then pass the
converted bech32 validator into contract.delegation; ensure any required utility
import is added and update tests/usage accordingly.

Comment on lines +81 to +83
// Default chain id to 7001 (ZetaChain testnet) when neither rpc nor chainId provided
const resolvedChainId = options.chainId || "7001";
const rpc = options.rpc || getRpcUrl(parseInt(resolvedChainId));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Verify that defaulting logic aligns with schema validation.

The function now defaults chainId to "7001" when neither rpc nor chainId is provided. However, baseZetachainOptionsRefined (lines 49-54) uses rpcOrChainIdRefineRule which appears to require at least one of these fields.

Since setupZetachainTransaction accepts SetupTxOptionsSubset (which doesn't enforce the refined rule), callers may bypass the schema validation and hit the default silently. This could cause unexpected behavior if users expect an error when omitting both options.

Verify that all callers of setupZetachainTransaction validate their options through baseZetachainOptionsRefined before calling this function, or update the function to throw an error when both rpc and chainId are undefined to maintain consistency with the schema's intent.

#!/bin/bash
# Description: Find all call sites of setupZetachainTransaction and check if they validate with baseZetachainOptionsRefined

# Search for function calls
rg -n --type ts 'setupZetachainTransaction\(' -A 3 -B 10
🤖 Prompt for AI Agents
In utils/zetachain.command.helpers.ts around lines 81 to 83, the code currently
defaults chainId to "7001" when both rpc and chainId are missing which can
silently bypass the refined schema rule; either (A) update all call sites to
validate their options with baseZetachainOptionsRefined before calling
setupZetachainTransaction (search for setupZetachainTransaction(...) and
insert/refactor validation using baseZetachainOptionsRefined and return/throw on
validation failure), or (B) change setupZetachainTransaction itself to enforce
the schema intent by detecting when both options.rpc and options.chainId are
undefined and throwing a clear error instead of defaulting, so callers cannot
silently bypass the refined rule.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zetachain z staking delegate zetachain query validators list

2 participants