Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ jobs:
run: ./sekai-cli scenario run examples/scenarios/ci-integration-test.yaml

- name: Run Go integration tests
run: go test -v -timeout 30m ./test/integration/...
run: go test -v -timeout 30m -p 1 ./test/integration/...

- name: Collect logs on failure
if: failure()
Expand Down
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A zero-dependency, SDK-first CLI for interacting with SEKAI blockchain.

## Features

- **222 SDK Commands** - Full coverage of all SEKAI blockchain modules
- **159 SDK Commands** - Full coverage of all SEKAI blockchain modules
- **Scenario Automation** - YAML-based playbooks for complex workflows
- **SDK-First Architecture** - Core logic in reusable `pkg/sdk/` library
- **Zero External Dependencies** - Uses only Go standard library
Expand Down Expand Up @@ -189,20 +189,24 @@ sekai-cli completion fish > ~/.config/fish/completions/sekai-cli.fish
| Module | Commands | Description |
|--------|----------|-------------|
| auth | 6 | Account queries |
| bank | 10 | Token transfers |
| bank | 7 | Token transfers and supply |
| basket | 16 | Token baskets |
| bridge | 4 | Cross-chain bridge |
| collectives | 11 | Collectives management |
| custody | 5 | Custody queries |
| custody | 4 | Custody queries |
| distributor | 5 | Fee distribution |
| gov | 82 | Governance (roles, proposals, voting) |
| keys | 16 | Key management |
| gov | 46 | Governance (roles, proposals, voting) |
| keys | 4 | Key management |
| layer2 | 3 | Layer2 dApps |
| multistaking | 13 | Multi-asset staking |
| spending | 12 | Spending pools |
| recovery | 4 | Recovery tokens |
| slashing | 6 | Slashing info |
| spending | 11 | Spending pools |
| staking | 4 | Validator staking |
| tokens | 7 | Token rates |
| ubi | 4 | Universal Basic Income |
| upgrade | 4 | Network upgrades |
| **Total** | **222** | |
| **Total** | **159** | |

## Development

Expand Down
109 changes: 109 additions & 0 deletions docs/COMMAND_COVERAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Command Coverage Tracking

This document tracks sekaid commands coverage in sekai-cli.

## Summary

| Category | sekaid | CLI | Mapper | Coverage |
|----------|--------|-----|--------|----------|
| Query commands | 98 | 98 | 98 | 100% |
| TX commands | 57 | 57 | 57 | 100% |
| Keys commands | 12 | 4 | 16 | CLI: 33%, Mapper: 100% |
| Node/Daemon commands | ~40 | 0 | 0 | N/A (not applicable) |
| **Total SDK commands** | **167** | **159** | **171** | **100%** |

- **CLI**: Direct command-line commands (`sekai-cli <module> <command>`)
- **Mapper**: Available via scenarios (`sekai-cli scenario run ...`)

## Not Implemented (By Design)

These sekaid commands are **not applicable** to sekai-cli (daemon/node operations):

### Node Operation Commands
- `start` - Start the node daemon
- `init` - Initialize node
- `gentx` - Generate genesis transaction
- `gentx-claim` - Claim validator in genesis
- `collect-gentxs` - Collect genesis transactions
- `add-genesis-account` - Add account to genesis
- `validate-genesis` - Validate genesis file
- `export` - Export state
- `export-metadata` - Export metadata
- `export-minimized-genesis` - Export minimized genesis
- `new-genesis-from-exported` - Create new genesis
- `bootstrap-state` - Bootstrap state
- `reset-state` - Reset state
- `rollback` - Rollback state
- `unsafe-reset-all` - Unsafe reset

### Tendermint/CometBFT Commands
- `tendermint` - Tendermint subcommands
- `show-node-id` - Show node ID
- `show-address` - Show address
- `show-validator` - Show validator info
- `tendermint-validator-set` - Query validator set

### Debug Commands
- `debug` - Debug subcommands
- `addr` - Address conversion
- `prefixes` - List HRP prefixes
- `pubkey` - Decode pubkey
- `pubkey-raw` - Decode raw pubkey
- `raw-bytes` - Convert raw bytes
- `val-address` - Get validator address
- `valcons-address` - Get validator consensus address

### Transaction Signing (Offline)
- `sign` - Sign transaction offline
- `sign-batch` - Sign batch offline
- `multi-sign` - Multi-signature
- `broadcast` - Broadcast signed tx
- `encode` - Encode transaction
- `decode` - Decode transaction
- `validate-signatures` - Validate signatures

### Other
- `config` - CLI configuration
- `help` - Help command
- `version` - Version info
- `testnet` - Setup testnet
- `rosetta` - Rosetta API

## Keys Commands Coverage

| sekaid | CLI | Mapper/Scenario | Status |
|--------|-----|-----------------|--------|
| `keys list` | ✅ | ✅ | Full |
| `keys show` | ✅ | ✅ | Full |
| `keys add` | ✅ | ✅ | Full |
| `keys delete` | ✅ | ✅ | Full |
| `keys export` | ❌ | ✅ | Scenario only |
| `keys import` | ❌ | ✅ | Scenario only |
| `keys import-hex` | ❌ | ✅ | Scenario only |
| `keys rename` | ❌ | ✅ | Scenario only |
| `keys mnemonic` | ❌ | ✅ | Scenario only |
| `keys migrate` | ❌ | ✅ | Scenario only |
| `keys parse` | ❌ | ✅ | Scenario only |
| `keys list-key-types` | ❌ | ✅ | Scenario only |
| `keys get-address` | ❌ | ✅ | Scenario only |
| `keys exists` | ❌ | ✅ | Scenario only |
| `keys create` | ❌ | ✅ | Scenario only |
| `keys recover` | ❌ | ✅ | Scenario only |

**Note**: All 16 keys commands are implemented in the mapper (usable via scenarios).
Only 4 are exposed as direct CLI commands.

## Query Commands - Full Coverage ✅

All query commands are implemented in sekai-cli.

## TX Commands - Full Coverage ✅

All transaction commands are implemented in sekai-cli.

## Notes

1. sekai-cli focuses on **SDK commands** (queries and transactions)
2. Node operation commands are handled by `sekaid` directly or via `scaller`
3. Keys commands have partial coverage - basic operations supported
4. Some commands exist in mapper with different names (aliases)
13 changes: 8 additions & 5 deletions test/integration/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ import (
// TestAuthAccount tests querying a single account by address.
func TestAuthAccount(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

ctx, cancel := getTestContext()
defer cancel()

mod := auth.New(client)
result, err := mod.Account(ctx, TestAddress)
result, err := mod.Account(ctx, testAddr)
requireNoError(t, err, "Failed to query account")
requireNotNil(t, result, "Account is nil")

// Verify account has expected fields
requireEqual(t, TestAddress, result.Address, "Address mismatch")
requireEqual(t, testAddr, result.Address, "Address mismatch")
requireTrue(t, result.AccountNumber != "", "Account number should not be empty")

t.Logf("Account: %s, Number: %s, Sequence: %s", result.Address, result.AccountNumber, result.Sequence)
Expand All @@ -32,6 +33,7 @@ func TestAuthAccount(t *testing.T) {
// TestAuthAccounts tests querying all accounts.
func TestAuthAccounts(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

Expand All @@ -51,7 +53,7 @@ func TestAuthAccounts(t *testing.T) {
// Verify the test address is in the list
found := false
for _, acc := range result.Accounts {
if acc.Address == TestAddress {
if acc.Address == testAddr {
found = true
break
}
Expand All @@ -62,6 +64,7 @@ func TestAuthAccounts(t *testing.T) {
// TestAuthAddressByAccNum tests querying an address by account number.
func TestAuthAddressByAccNum(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

Expand All @@ -71,7 +74,7 @@ func TestAuthAddressByAccNum(t *testing.T) {
mod := auth.New(client)

// First get the account to know its account number
acc, err := mod.Account(ctx, TestAddress)
acc, err := mod.Account(ctx, testAddr)
requireNoError(t, err, "Failed to query account")
requireNotNil(t, acc, "Account is nil")

Expand All @@ -80,7 +83,7 @@ func TestAuthAddressByAccNum(t *testing.T) {
requireNoError(t, err, "Failed to query address by account number")
requireNotNil(t, result, "Result is nil")

requireEqual(t, TestAddress, result.AccountAddress, "Address mismatch")
requireEqual(t, testAddr, result.AccountAddress, "Address mismatch")
t.Logf("Account number %s maps to address %s", acc.AccountNumber, result.AccountAddress)
}

Expand Down
18 changes: 11 additions & 7 deletions test/integration/bank_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@ import (
// TestBankBalances tests querying all balances for an address.
func TestBankBalances(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

ctx, cancel := getTestContext()
defer cancel()

mod := bank.New(client)
result, err := mod.Balances(ctx, TestAddress)
result, err := mod.Balances(ctx, testAddr)
requireNoError(t, err, "Failed to query balances")

t.Logf("Address %s has %d token types", TestAddress, len(result))
t.Logf("Address %s has %d token types", testAddr, len(result))
for _, coin := range result {
t.Logf(" %s: %s", coin.Denom, coin.Amount)
}
Expand All @@ -32,35 +33,37 @@ func TestBankBalances(t *testing.T) {
// TestBankBalance tests querying balance for a specific denom.
func TestBankBalance(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

ctx, cancel := getTestContext()
defer cancel()

mod := bank.New(client)
result, err := mod.Balance(ctx, TestAddress, "ukex")
result, err := mod.Balance(ctx, testAddr, "ukex")
requireNoError(t, err, "Failed to query balance")
requireNotNil(t, result, "Balance is nil")

requireEqual(t, "ukex", result.Denom, "Denom mismatch")
t.Logf("Address %s has %s ukex", TestAddress, result.Amount)
t.Logf("Address %s has %s ukex", testAddr, result.Amount)
}

// TestBankSpendableBalances tests querying spendable balances.
func TestBankSpendableBalances(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

ctx, cancel := getTestContext()
defer cancel()

mod := bank.New(client)
result, err := mod.SpendableBalances(ctx, TestAddress)
result, err := mod.SpendableBalances(ctx, testAddr)
requireNoError(t, err, "Failed to query spendable balances")

t.Logf("Address %s has %d spendable token types", TestAddress, len(result))
t.Logf("Address %s has %d spendable token types", testAddr, len(result))
for _, coin := range result {
t.Logf(" %s: %s", coin.Denom, coin.Amount)
}
Expand Down Expand Up @@ -154,7 +157,8 @@ func TestBankSend(t *testing.T) {
t.Logf("Recipient address: %s", recipientAddr)

// Get initial balances
senderBalanceBefore, err := bankMod.Balance(ctx, TestAddress, "ukex")
testAddr := getTestAddress(t)
senderBalanceBefore, err := bankMod.Balance(ctx, testAddr, "ukex")
requireNoError(t, err, "Failed to query sender balance")
t.Logf("Sender balance before: %s ukex", senderBalanceBefore.Amount)

Expand Down
3 changes: 2 additions & 1 deletion test/integration/basket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ func TestBasketProposalWithdrawSurplus(t *testing.T) {
Description: "Integration test - verify withdraw surplus proposal",
}

resp, err := mod.ProposalWithdrawSurplus(ctx, TestKey, "1", TestAddress, propOpts, nil)
testAddr := getTestAddress(t)
resp, err := mod.ProposalWithdrawSurplus(ctx, TestKey, "1", testAddr, propOpts, nil)
if err != nil {
t.Logf("ProposalWithdrawSurplus may have failed (no basket): %v", err)
return
Expand Down
12 changes: 8 additions & 4 deletions test/integration/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import (
// TestBridgeGetCosmosEthereum tests querying cosmos to ethereum changes.
func TestBridgeGetCosmosEthereum(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

ctx, cancel := getTestContext()
defer cancel()

mod := bridge.New(client)
result, err := mod.GetCosmosEthereum(ctx, TestAddress)
result, err := mod.GetCosmosEthereum(ctx, testAddr)
if err != nil {
// This may fail if no bridge changes exist
t.Logf("Cosmos to Ethereum query: %v (expected if no changes)", err)
Expand All @@ -30,14 +31,15 @@ func TestBridgeGetCosmosEthereum(t *testing.T) {
// TestBridgeGetEthereumCosmos tests querying ethereum to cosmos changes.
func TestBridgeGetEthereumCosmos(t *testing.T) {
skipIfContainerNotRunning(t)
testAddr := getTestAddress(t)
client := getTestClient(t)
defer client.Close()

ctx, cancel := getTestContext()
defer cancel()

mod := bridge.New(client)
result, err := mod.GetEthereumCosmos(ctx, TestAddress)
result, err := mod.GetEthereumCosmos(ctx, testAddr)
if err != nil {
// This may fail if no bridge changes exist
t.Logf("Ethereum to Cosmos query: %v (expected if no changes)", err)
Expand All @@ -59,7 +61,8 @@ func TestBridgeChangeCosmosEthereum(t *testing.T) {
mod := bridge.New(client)

// Use test values
cosmosAddress := TestAddress
testAddr := getTestAddress(t)
cosmosAddress := testAddr
ethAddress := "0x1234567890123456789012345678901234567890"
amount := "100ukex"

Expand Down Expand Up @@ -88,7 +91,8 @@ func TestBridgeChangeEthereumCosmos(t *testing.T) {
mod := bridge.New(client)

// Use test values
cosmosAddress := TestAddress
testAddr := getTestAddress(t)
cosmosAddress := testAddr
ethTxHash := "0x" + generateUniqueID("txhash")
amount := "100ukex"

Expand Down
Loading