# Secure validator with HW wallet

{% hint style="info" %}

> The steps below show how to do this using the command-line interface (CLI). Alternatively, you can use [validator.x1.wiki](https://validator.x1.wiki/) for a simple web-based way to replace your id.json with a hardware wallet.
> {% endhint %}

## Step 1 — Check your current vote account (server)

On your **server**:

```sh
solana show-vote-account <VOTE_PUBKEY>
```

Confirm the **Withdraw Authority** matches the `id.json` key you plan to replace.

Verify the pubkey of `id.json`:

```sh
solana-keygen pubkey ~/.config/solana/id.json
```

> This ensures you’re confirming the correct `id.json` key before updating its withdraw authority.

***

## Step 2 — Get your Ledger’s public key (on your computer)

Plug in your Ledger, open the **Solana** app, and run:

```
solana-keygen pubkey "usb://ledger?key=0/0"
```

Copy the output — this is your **Ledger withdraw authority address**:

```
<LEDGER_PUBKEY>
```

> You only need the **public key**. No Ledger connection is required on the server.

***

## Step 3 — Set your RPC cluster (server)

Example for **X1 testnet**:

```
solana config set --url https://rpc.testnet.x1.xyz
```

***

## Step 4 — Change the withdraw authority (server)

Run this **on the server**:

```
solana vote-authorize-withdrawer-checked \
  <VOTE_PUBKEY> \
  ~/.config/solana/id.json \
  <LEDGER_PUBKEY> \
  --fee-payer ~/.config/solana/id.json \
  --url https://rpc.testnet.x1.xyz
```

* Signs with your **current withdraw authority** (`id.json`)
* Assigns your **Ledger** as the new withdraw authority
* Pays the transaction fee from the same account

> You are changing **who can withdraw rewards**. Validator operations are unaffected.

***

## Step 5 — Verify on-chain (server or computer)

```
solana show-vote-account <VOTE_PUBKEY> --url https://rpc.testnet.x1.xyz | grep "Withdraw Authority"
```

You should see:

```
Withdraw Authority: <LEDGER_PUBKEY>
```

***

## Step 6 — Back up and clean up (server)

### 🔐 Back up `id.json` safely

Create a structured backup and store it in your password manager or encrypted vault:

```
mkdir -p ~/X1-backups/keys
cp ~/.config/solana/id.json ~/X1-backups/keys/

PUBKEY=$(solana-keygen pubkey ~/X1-backups/keys/id.json)
SHA256=$(shasum -a 256 ~/X1-backups/keys/id.json | awk '{print $1}')

cat > ~/X1-backups/keys/id_key_metadata.txt <<EOF
--- PRIVATE KEY (id.json) ---
$(cat ~/X1-backups/keys/id.json)

--- PUBLIC KEY ---
$PUBKEY

--- SHA256 (file checksum) ---
$SHA256
EOF
```

If you’re on macOS:

```
pbcopy < ~/X1-backups/keys/id_key_metadata.txt
echo "✅ id_key_metadata.txt copied to clipboard — paste it into your password manager."
```

***

### 🔒 Tighten permissions

```
chmod 700 ~/.config/solana
chmod 600 ~/.config/solana/*.json
```

> This ensures only your current Linux user can access key files — protecting against accidental leaks or unauthorized reads.

***

## Final State

| Role                     | File / Address             | Description                                          |
| ------------------------ | -------------------------- | ---------------------------------------------------- |
| Validator identity       | `identity.json`            | Operates the validator node                          |
| Vote account             | `vote.json`                | Account linked to validator for consensus/rewards    |
| Withdraw authority (new) | **Ledger hardware wallet** | Securely holds withdraw rights                       |
| Withdraw authority (old) | `id.json` (backed up)      | Former hot key, no longer used as withdraw authority |

***

## Troubleshooting

* **“insufficient funds for fee”**\
  `id.json` has 0 balance. Send a small amount of testnet XNT to it before retrying.
* **“Signature verification failed”**\
  `id.json` is not the current withdraw authority for this vote account, or you’re pointed at the wrong cluster.
* **“This account may not be used to pay transaction fees”**\
  You tried to use a restricted account (e.g., validator identity) as fee-payer. Use a normal wallet or `id.json` itself.
