Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 67 additions & 10 deletions x/observer/client/cli/query_get_tss_address.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,68 @@
package cli

import (
"fmt"
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/spf13/cobra"

"github.com/zeta-chain/node/pkg/chains"
"github.com/zeta-chain/node/x/observer/types"
)

// btcNetworks lists all supported Bitcoin networks for TSS address display.
var btcNetworks = []struct {
Name string
ChainID int64
}{
{"mainnet", chains.BitcoinMainnet.ChainId},
{"testnet3", chains.BitcoinTestnet.ChainId},
{"signet", chains.BitcoinSignetTestnet.ChainId},
{"testnet4", chains.BitcoinTestnet4.ChainId},
{"regtest", chains.BitcoinRegtest.ChainId},
}

func CmdGetTssAddress() *cobra.Command {
cmd := &cobra.Command{
Use: "get-tss-address [bitcoinChainId]]",
Use: "get-tss-address [bitcoinChainId]",
Short: "Query current tss address",
Args: cobra.MaximumNArgs(1),
Long: `Query current TSS addresses for EVM, Sui, and Bitcoin.

Without arguments, prints the EVM and Sui addresses once, and the Bitcoin address for all
supported networks (mainnet, testnet3, signet, testnet4, regtest).

With a bitcoinChainId argument, prints only the Bitcoin address for that specific chain.

Examples:
zetacored query observer get-tss-address
zetacored query observer get-tss-address 18333`,
Comment on lines +31 to +40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Help text does not match the single-chain behavior.

Line 36 says this mode prints only the Bitcoin address, but Lines 55-61 still print the full query response. Please either narrow the output or update the help text to describe the actual behavior.

Suggested wording
-With a bitcoinChainId argument, prints only the Bitcoin address for that specific chain.
+With a bitcoinChainId argument, prints the TSS addresses, using that Bitcoin chain ID to derive the BTC address.

Also applies to: 55-61

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/observer/client/cli/query_get_tss_address.go` around lines 31 - 40, The
help text (the Long string in query_get_tss_address.go) claims that giving a
bitcoinChainId prints only the Bitcoin address, but the command's handler still
prints the full query response in the bitcoin-argument branch (the printing
block that handles bitcoinChainId in the command's RunE/handler). Fix by either
(A) updating the Long string to accurately describe that the full response is
printed even when a bitcoinChainId is supplied, or (B) change the handler
printing logic so when a bitcoinChainId argument is provided it filters the
query response and prints only the Bitcoin address for that chain (modify the
bitcoin-argument branch in the RunE/handler to extract and print the single
address instead of printing the entire response). Ensure you update the same
Long text and the bitcoin-argument printing branch so both behavior and help
text remain consistent.

Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
params := &types.QueryGetTssAddressRequest{}

// If a specific chain ID is provided, use the original single-query behavior
if len(args) == 1 {
bitcoinChainID, err := strconv.ParseInt(args[0], 10, 64)
if err != nil {
return err
}
params.BitcoinChainId = bitcoinChainID
}

res, err := queryClient.GetTssAddress(cmd.Context(), params)
if err != nil {
return err
res, err := queryClient.GetTssAddress(cmd.Context(), &types.QueryGetTssAddressRequest{
BitcoinChainId: bitcoinChainID,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
}

return clientCtx.PrintProto(res)
// No args: print EVM/Sui once, then BTC for all networks
return printAllTSSAddresses(cmd, queryClient)
},
}

Expand All @@ -44,6 +71,36 @@ func CmdGetTssAddress() *cobra.Command {
return cmd
}

// printAllTSSAddresses queries TSS addresses for all BTC networks and prints them.
func printAllTSSAddresses(cmd *cobra.Command, queryClient types.QueryClient) error {
// Query with first BTC network to get EVM and Sui addresses
first := btcNetworks[0]
res, err := queryClient.GetTssAddress(cmd.Context(), &types.QueryGetTssAddressRequest{
BitcoinChainId: first.ChainID,
})
if err != nil {
return err
}

fmt.Printf("eth: %s\n", res.Eth)
fmt.Printf("sui: %s\n", res.Sui)
fmt.Printf("btc (%s, %d): %s\n", first.Name, first.ChainID, res.Btc)

// Query remaining BTC networks
for _, net := range btcNetworks[1:] {
btcRes, err := queryClient.GetTssAddress(cmd.Context(), &types.QueryGetTssAddressRequest{
BitcoinChainId: net.ChainID,
})
if err != nil {
fmt.Printf("btc (%s, %d): error: %v\n", net.Name, net.ChainID, err)
continue
}
fmt.Printf("btc (%s, %d): %s\n", net.Name, net.ChainID, btcRes.Btc)
Comment on lines +75 to +98
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the file
find . -name "query_get_tss_address.go" -type f

Repository: zeta-chain/node

Length of output: 107


🏁 Script executed:

# Read the file to see the actual code and context
cat -n x/observer/client/cli/query_get_tss_address.go | head -120

Repository: zeta-chain/node

Length of output: 4519


🏁 Script executed:

# Search for other CLI query functions to see the pattern used for output
rg "OutOrStdout\|Printf" x/observer/client/cli/ -n -A 2 -B 2 | head -100

Repository: zeta-chain/node

Length of output: 41


🏁 Script executed:

# Check for Cobra usage patterns in this CLI directory
fd "\.go$" x/observer/client/cli/ -x grep -l "cmd.Out" {} \;

Repository: zeta-chain/node

Length of output: 41


🏁 Script executed:

# Search for output patterns in CLI queries
rg "Print|Printf|OutOrStdout|cmd\.Out" x/observer/client/cli/ --type go -n | head -50

Repository: zeta-chain/node

Length of output: 2848


🏁 Script executed:

# Check other query commands in the same directory
find x/observer/client/cli -name "query_*.go" -type f

Repository: zeta-chain/node

Length of output: 716


🏁 Script executed:

# Look at how other commands handle output - check a few similar query files
cat -n x/observer/client/cli/query.go | head -100

Repository: zeta-chain/node

Length of output: 1697


🏁 Script executed:

# Check if clientCtx.PrintProto is the standard pattern used elsewhere
rg "clientCtx\.Print|PrintProto" x/observer/client/cli/ --type go -n -B 2 -A 2 | head -80

Repository: zeta-chain/node

Length of output: 4093


Make the no-arg path use the same output layer as the single-chain branch.

Lines 85–98 use direct fmt.Printf output, creating an inconsistency within the same command. The single-chain path (line 61) routes output through clientCtx.PrintProto(res), which respects the configured output format and Cobra's output writer. The no-arg path should do the same by using clientCtx.PrintProto() to ensure consistent behavior, proper scripting support, and adherence to the established codebase pattern used throughout other query commands in this module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/observer/client/cli/query_get_tss_address.go` around lines 75 - 98, The
no-arg branch in printAllTSSAddresses currently uses fmt.Printf for output;
change it to use the same client output path as the single-chain branch by
getting clientCtx := client.GetClientContextFromCmd(cmd) and calling
clientCtx.PrintProto(...) instead of fmt.Printf. Specifically, replace the
fmt.Printf("eth: ..."), fmt.Printf("sui: ..."), and fmt.Printf("btc (...) :
...") calls to print the QueryGetTssAddressResponse (res) via
clientCtx.PrintProto(res) and likewise print each btcRes with
clientCtx.PrintProto(btcRes) (or aggregate into a single proto message and
PrintProto) so output respects configured format and Cobra's output writer.
Ensure errors still print to the command writer (use
fmt.Fprintf(cmd.OutOrStdout(), ...) or return the error) consistent with other
query commands.

}

return nil
Comment on lines +89 to +101
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not return success after partial network failures.

Lines 94-96 downgrade per-network query failures to text and continue, but Line 101 still returns nil. Any automation invoking this command will get exit code 0 even when some BTC addresses were not retrieved. Consider collecting the failed networks and returning a combined error after printing the successful rows.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/observer/client/cli/query_get_tss_address.go` around lines 89 - 101, The
loop over btcNetworks in the function using queryClient.GetTssAddress currently
prints per-network errors and continues, but the function still returns nil;
instead, track failures (e.g., collect failed net identifiers into a slice)
while continuing to print successes, and after the loop return a non-nil error
if any failures occurred (e.g., fmt.Errorf with the list of failed networks).
Update the function that performs the loop (references: btcNetworks,
queryClient.GetTssAddress, btcRes) to accumulate failed networks and return a
combined error after printing all results rather than returning nil on partial
failures.

}

func CmdGetTssAddressByFinalizedZetaHeight() *cobra.Command {
cmd := &cobra.Command{
Use: "get-historical-tss-address [finalizedZetaHeight] [bitcoinChainId]",
Expand Down
Loading