> For the complete documentation index, see [llms.txt](https://nytshift.gitbook.io/nytshift-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://nytshift.gitbook.io/nytshift-docs/hyperliquid/hyperliquid-testnet-signer.md).

# Testnet signer supervisor

Use this runbook only to prepare and inspect the isolated Hyperliquid signer process. It does not authorize a venue request or a testnet order. Stop before any execution rehearsal unless the user has explicitly approved that exact external action.

## Safety contract

* Use a dedicated Hyperliquid **API wallet** for this process. Never use or copy the owner/master-wallet private key.
* Register the API wallet on Hyperliquid testnet through the owner-controlled venue flow before any later trading rehearsal.
* Store the API-wallet private key in a locked-down regular file outside this repository. Do not paste it into the shell, `.env`, browser, chat, logs or command arguments.
* Keep `ALLOW_MAINNET=false` and `ARCUS_ALLOW_MAINNET=false` throughout this testnet procedure. The supervisor refuses a mismatched mainnet flag and any active Arcus execution mode. Mainnet uses the separate reviewed promotion procedure after the testnet matrix passes.
* Use a high-entropy internal bearer token that is different from operator-session and one-use confirmation secrets.
* Treat healthy process state as infrastructure evidence only. It is not eligibility, funding, builder approval or order authority.

## Prepare the environment

Configure values in the operator-owned service environment or the current PowerShell session. Addresses must be the exact lowercase reviewed values.

```powershell
$env:EXECUTION_MODE = "testnet"
$env:ALLOW_MAINNET = "false"
$env:ARCUS_EXECUTION_MODE = "disabled"
$env:ARCUS_ALLOW_MAINNET = "false"
$env:HL_ACCOUNT_ADDRESS = "0x<lowercase-master-or-subaccount-address>"
$env:NIGHTSHIFT_HL_OWNER_ADDRESS = "0x<lowercase-owning-master-address>"
$env:HL_AGENT_PRIVATE_KEY_PATH = "C:\secure\nightshift\hl-testnet-api-wallet.key"
$env:NIGHTSHIFT_HL_BUILDER_ADDRESS = "0x<lowercase-reviewed-builder-address>"
$env:NIGHTSHIFT_HL_BUILDER_FEE_TENTHS_BPS = "20"
$env:INTERNAL_EXECUTION_TOKEN = "<random-high-entropy-bearer-token>"
$env:NIGHTSHIFT_HL_SIGNER_PORT = "4300"
```

The key file must contain one 32-byte secp256k1 private key encoded as `0x` plus 64 hexadecimal characters, followed by an optional newline. Restrict its ACL to the signer service identity. Set `NIGHTSHIFT_HL_OWNER_ADDRESS` to the same value as `HL_ACCOUNT_ADDRESS` for a master account, or to the owning master address for a subaccount. The doctor rejects a key derived to either the owner or selected account scope.

The signed execution-eligibility public key and decision file are a separate authority. Configure them only after the eligibility issuer procedure has produced an exact, current testnet/account decision. Never place the eligibility issuer private key in the signer environment.

## Offline doctor

```powershell
pnpm hl-signer:doctor
```

Expected evidence:

* `status: "ready"`
* `venue: "hyperliquid"`
* `mode: "testnet"`
* `networkRequests: 0`
* redacted account, owner, API-wallet and builder fingerprints
* `keyType: "secp256k1"`

The doctor must fail if the key is inline, symlinked, inside the repository, malformed, resolves to the explicit master/owner or selected account address, or if either venue can reach mainnet. Do not weaken these checks to make a key pass.

## Start and inspect

```powershell
pnpm hl-signer:start
pnpm hl-signer:status
pnpm hl-signer:health
```

The supervisor binds only `127.0.0.1:4300` by default. The authenticated, redacted health result must match the configured testnet account and builder fingerprints and report:

* `mode: testnet` and `signingEnabled: true`;
* `databaseSchemaVersion: 8`, `databaseSchemaCurrent: true`, `databaseIntegrity: "ok"` and `databaseJournalMode: "wal"`;
* the exact signed-eligibility state, which may safely be unconfigured or inactive;
* the exact dead-man-switch state, which may safely be unconfigured and not armed;
* no raw account, owner, builder, key path, private key, internal token or eligibility token.

An unauthenticated request to the signer health endpoint must return `401`. Do not expose this loopback service through Nginx, a tunnel, Cloudflare or a public bind.

## Install the reboot-safe Linux service

The VPS service is deliberately separate from the public web release and must run as its own non-login identity. Preparing the service files does not create an API wallet or authorize a venue action.

From the exact reviewed Git commit, create an immutable signer-tools release, install only its locked Python environment, and promote the symlink atomically:

```bash
commit="$(git rev-parse --verify HEAD^{commit})"
sudo install -d -o root -g root -m 0755 "/opt/nytshift/signer-tools/$commit"
git archive "$commit" | sudo tar -x -C "/opt/nytshift/signer-tools/$commit"
sudo chown -R root:root "/opt/nytshift/signer-tools/$commit"
sudo find "/opt/nytshift/signer-tools/$commit" -type d -exec chmod 0755 {} +
sudo find "/opt/nytshift/signer-tools/$commit" -type f -exec chmod 0644 {} +
sudo uv sync --project "/opt/nytshift/signer-tools/$commit/services/execution-py" --frozen --no-dev
sudo ln -sfn "/opt/nytshift/signer-tools/$commit" /opt/nytshift/signer-tools/current.next
sudo mv -Tf /opt/nytshift/signer-tools/current.next /opt/nytshift/signer-tools/current
```

Create the service identity and private directories once:

```bash
sudo useradd --system --user-group --home-dir /var/lib/nytshift-hyperliquid-signer --shell /usr/sbin/nologin nytshift-signer
sudo install -d -o root -g nytshift-signer -m 0750 /etc/nytshift-hyperliquid-signer
sudo install -o root -g nytshift-signer -m 0640 infra/systemd/nytshift-hyperliquid-signer.env.example /etc/nytshift-hyperliquid-signer/environment
sudo install -o root -g root -m 0644 infra/systemd/nytshift-hyperliquid-signer.service /etc/systemd/system/
```

Fill the environment file locally on the VPS as root. Keep `EXECUTION_MODE=testnet`, both mainnet flags false, and leave the service stopped until the exact lowercase account, owning master, reviewed builder, dedicated registered API-wallet key path, independent eligibility evidence and random internal token are available. The key file must be `root:nytshift-signer` mode `0640`; it must never be copied into the signer-tools release.

Before enabling anything, verify the unit and run the offline doctor under the service identity:

```bash
sudo systemd-analyze verify /etc/systemd/system/nytshift-hyperliquid-signer.service
sudo systemctl daemon-reload
sudo systemctl start nytshift-hyperliquid-signer.service
sudo systemctl status --no-pager nytshift-hyperliquid-signer.service
```

`ExecStartPre` runs the zero-network doctor. An incomplete template, wrong key ownership/scope, active Arcus mode, mismatched account, unsafe mainnet flag or malformed eligibility evidence makes the unit fail before the signer child starts. Do not enable the unit at boot until the separately authorized testnet rehearsal is ready and its cold-backup procedure has been reviewed.

To stop the service cleanly:

```bash
sudo systemctl stop nytshift-hyperliquid-signer.service
```

The service uses `KillMode=mixed`: the supervisor receives the graceful stop signal first and systemd kills the full cgroup only if the bounded stop window expires. Its state survives restarts under `/var/lib/nytshift-hyperliquid-signer`; the key and service environment remain outside that directory.

## Recovery rehearsal

The integration test uses an ephemeral test key and never contacts Hyperliquid:

```powershell
pnpm test:hl-signer
```

It proves authenticated health, exclusion by the shared signer-store lock, bounded child recovery and clean shutdown. It also scans state and logs for the test key, token, full account/builder address and key path. This is process proof only.

For an operator rehearsal, record the supervisor generation and child PID, terminate only the child, and confirm that one new generation becomes healthy within the configured startup and health windows. If repeated failures reach the per-minute restart budget, the supervisor remains fail-closed during its cooldown; stop it and investigate the fixed reason code instead of waiting through a crash loop. Never compensate by relaxing health or widening the bind.

## Connect the web control plane later

Only after the signer is healthy and the separate eligibility procedure is complete, configure the server-only web process with:

```powershell
$env:EXECUTION_SERVICE_URL = "http://127.0.0.1:4300"
```

The web process must not receive `HL_AGENT_PRIVATE_KEY`, `HL_AGENT_PRIVATE_KEY_PATH`, the signer token in any client-visible variable, or an eligibility issuer private key. Keep operator authentication, one-use confirmation, allowlist, kill switch, risk limits and signed eligibility as independent controls.

Do not proceed from health inspection to an order. Follow [`hyperliquid-go-live-validation.md`](/nytshift-docs/hyperliquid/hyperliquid-go-live-validation.md): its no-send readiness command rechecks the control-plane gates, and every later testnet mutation still requires explicit action-time user authorization.

After the complete testnet matrix is reviewed, follow [`hyperliquid-mainnet-signer.md`](/nytshift-docs/hyperliquid/hyperliquid-mainnet-signer.md). Do not repurpose this testnet environment in place without first stopping the signer, verifying a cold signer-store backup and reviewing every changed scope.

## Stop

```powershell
pnpm hl-signer:stop
pnpm hl-signer:status
```

Stop the supervisor before backup, restore, key rotation, scope changes or service-environment edits. The shared operation lock deliberately prevents signer-store backup/restore while either the Arcus or Hyperliquid signer is running.

## Incident response

1. Set/keep the web execution kill switch active and stop new approvals.
2. Do not restart or retry an ambiguous venue mutation. Reconcile by exact retained CLOID/order/fill evidence.
3. If the key may be exposed, stop the signer and revoke the API wallet through the owner-controlled Hyperliquid flow; do not paste the owner key into NIGHTSHIFT.
4. Preserve the execution database, WAL, supervisor state and bounded logs without publishing them.
5. Restore only with the documented signer-store procedure and verify schema, integrity, WAL and reconciliation latches before another start.
6. Require a new API wallet and a new exact eligibility decision after key rotation.

## Official references

* <https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api>
* <https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/nonces-and-api-wallets>
* <https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/signing>
* <https://github.com/hyperliquid-dex/hyperliquid-python-sdk>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://nytshift.gitbook.io/nytshift-docs/hyperliquid/hyperliquid-testnet-signer.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
