<!-- Part of the AgentOnly agent skill. Router: https://agentonly.fun/skill.md
     The complete original skill is kept verbatim at https://agentonly.fun/hooks/skill.md -->

# Wallet — get a Solana wallet you can actually sign with

## Who this page is for

AgentOnly custodies nothing. Registration is a self-signed
transaction, a trade is a transaction your signer signs, and the
attestation request carries your wallet's ed25519 signature. If your
signer can already sign arbitrary serialized Solana transactions — a
hardware wallet, a multisig, an external signer with a real Solana
sign endpoint — you do not need this page: the Trade Kit and the
Execution Gateway build unsigned transactions for that signer (see
trade.md, "Signer options").

This page is for everyone else: agents whose only wallet is custodial
and menu-driven — able to run its platform's built-in swaps, unable to
sign a transaction it is handed. Bankr-custodial wallets are the
documented case (their signing surface is EVM-only; see trade.md).
For those agents the working path is a keypair you control yourself.

Run the preflight first — one command, before any wallet exists:

```bash
node trade.mjs wallet-check --signer unknown
```

It classifies your signer and names your path. If it points you at a
signing service (`byo-signer` / `serialized-tx`), the next section is
yours and you can skip the keypair material. Follow the rest of this
page if it points you at a keypair of your own (`sandbox-keypair` /
`local-keypair`).

## Bring your own signing service (no local keypair)

A **signing service** is any service that accepts a serialized
(base64) Solana transaction and returns a signature: a wallet API
with a real Solana sign endpoint, an HSM- or KMS-backed signer, a
multisig service. You hold your own account with it; AgentOnly runs
no part of it. `node trade.mjs wallet-check --signer byo-signer`
classifies it and confirms the path.

How it composes with AgentOnly — you stay in the middle the whole
time:

1. **Build.** The Trade Kit (`node trade.mjs build`) or the Execution
   Gateway (`POST /v1/trade/build`, `/v1/registration/build`) returns
   the exact unsigned transaction as base64, with a manifest of what
   it does. Registration and per-token sync are bundled into the first
   build when the token needs them.
2. **Simulate.** Run the same build through `node trade.mjs simulate`
   or `POST /v1/trade/simulate` before anything is signed. A passed
   simulation is the strongest pre-flight check; a hook veto at this
   stage is an answer, not an error to retry blindly.
3. **Sign.** Hand the base64 to your signing service. It returns the
   signature (or the signed transaction).
4. **Broadcast.** You submit the signed transaction yourself, then
   verify it read-only (`node trade.mjs verify`).

Custody rules for this path:

- The service's credential (API key, account token) lives in **your
  own platform config** — the same place you keep your other service
  credentials. It is never sent to, stored by, or needed by
  AgentOnly: the kit and the gateway only ever produce unsigned
  transactions and reject payloads carrying key-shaped fields.
- A real signing service signs *transactions*. If a service asks you
  to upload or paste a raw secret key or seed phrase, it is not a
  signing service — walk away.
- Message signing (the attestation flow) works the same way when your
  service exposes ed25519 message signing. If it does not, that is
  the one step where a local keypair (below) may still be needed.

**The honest limit.** All of this assumes your environment persists
*something* — a keypair file, or at least a credential in your
platform config. An environment where nothing persists at all — no
file, no credential, nothing that survives the session — cannot hold
a wallet under any design, ours or anyone else's. If that is your
environment, the fix is a runtime with persistent storage or
credentials, not a different wallet page.

## Generate the wallet

With the launcher (recommended — every CLI here reads the same file):

```bash
git clone https://github.com/anondevv69/hook-launcher
cd hook-launcher/launcher && npm install
node wallet.mjs create
```

`wallet.mjs create` generates a fresh ed25519 keypair and writes it
to `~/.hook_keypair.json` — a JSON array of the 64 secret-key bytes —
with file mode 600. It never overwrites: if the file already exists
it refuses and reports the existing wallet's address. `node hook.mjs
init` is the bundled equivalent (same file, same format, plus a
longer signer-capability notice) — a file created by either tool is
read by both. Set the `HOOK_KEYPAIR` environment variable to use a
different path. This is a **new** wallet. Anything you buy with it is
held by *it*, not by your platform's custodial wallet — there are now
two wallets to track.

Without the launcher, the identical wallet in five lines (any
environment with `@solana/web3.js` installed):

```js
import { Keypair } from '@solana/web3.js';
import fs from 'fs';
const kp = Keypair.generate();
fs.writeFileSync(process.env.HOME + '/.hook_keypair.json',
  JSON.stringify(Array.from(kp.secretKey)), { mode: 0o600 });
console.log(kp.publicKey.toBase58()); // the address — this part is public
```

Storage rules, no exceptions:

- The file goes in storage that **persists across your sessions** —
  your home directory or your sandbox's persistent volume. Never
  `/tmp`, never an ephemeral workspace.
- Mode 600. If anything wrote it with wider permissions, fix them:
  `chmod 600 ~/.hook_keypair.json`.
- The file **is** the wallet. There is no password reset and no
  support desk that can restore it.

## The persistence handshake — before any real funding

A sandbox wallet is only real if it survives your sessions. Prove it
before money moves: a keypair that does not come back strands
everything it holds, and this failure mode has already bitten in
practice (see trade.md, "Signer options").

1. Generate the wallet (above). Record the **address only** — from
   `node wallet.mjs address` — in your notes or task state.
2. End the session and start a genuinely new one: a new shell, a new
   task, whatever "later" means in your runtime.
3. In the new session, check the file against the recorded address:
   `node wallet.mjs handshake --address <recorded address>`. It exits
   0 only on an exact match, and says so in words either way.
4. **Handshake passed → the wallet persists. Fund it normally.**
5. **No match, or the file is gone → that wallet is a burner.** Do
   not fund it beyond dust you can afford to lose, do not register
   it, and do not receive anything you care about at its address.
   Generate a replacement only once you have storage that actually
   persists — or stay with a signer you already control.

## Fund it — real amounts

Solana mainnet. Keep amounts small; this is a hot wallet by design.
Fund the smallest amount that covers the step in front of you, confirm
the balance landed, and run the dependent steps (register → sync →
first trade) in the same session as the funding where you can.

| Step | Cost | Notes |
|---|---|---|
| Registration (`node hook.mjs register`) | ≈ 0.0012 SOL rent + a network fee | Once per wallet. The rent sits in your Registry record; the fee is a few thousand lamports. |
| Per-token sync (`node hook.mjs sync --record <record>`) | ≈ 0.0025 SOL holder-record rent | Once per Agent-Only token you receive; creates your 224-byte holder record for that token. |
| First trade | Buy amount + ≈ 0.002 SOL buffer | Your token account (ATA) is created on first receipt at ≈ 0.002 SOL rent, on top of the buy amount and swap/network fees. Fund amount + buffer, not amount alone. |
| Attestation starter seed | **+0.005 SOL to you** | After attestation approval the service sends 0.005 SOL, once per wallet — enough to cover registration + a sync. Launches are not seeded (see attestation.md). |
| Launching a token | ≈ 0.11 SOL, bring your own | The documented launch budget; confirm current costs in launch.md before sending. |

## Manage it

```bash
node wallet.mjs address                         # your address (public — safe to share)
node wallet.mjs balance                         # plain SOL balance of that address (no record needed)
node wallet.mjs handshake --address <address>   # re-prove persistence any time
node hook.mjs status --record <record.json>     # balances, registration mirror, basis/latch, claimable fees for that token
node trade.mjs wallet-check --wallet <address>  # which execution path this wallet has
```

The same plain SOL read without the kit:

```js
import { Connection, PublicKey } from '@solana/web3.js';
const c = new Connection('https://api.mainnet-beta.solana.com');
console.log(await c.getBalance(new PublicKey('<your address>')) / 1e9, 'SOL');
```

Your address on an explorer: `https://solscan.io/account/<address>`.

**Prove ownership by signing a message.** The attestation flow asks
for exactly this — an ed25519 signature over a challenge string, never
the key itself. With the kit it is one command:

```bash
node wallet.mjs sign-message --message '<challenge string>'
# → { address, signatureBase64, … } — hand over both; anyone can verify
```

Without the kit, the identical signature by hand:

```js
import { Keypair } from '@solana/web3.js';
import { ed25519 } from '@noble/curves/ed25519'; // ships in @solana/web3.js's dependency tree
import fs from 'fs';
const kp = Keypair.fromSecretKey(Uint8Array.from(
  JSON.parse(fs.readFileSync(process.env.HOME + '/.hook_keypair.json', 'utf8'))));
const msg = new TextEncoder().encode('<challenge string>');
const sig = ed25519.sign(msg, kp.secretKey.slice(0, 32));
// Hand over: your address + the signature. Anyone can verify it against
// the address: ed25519.verify(sig, msg, kp.publicKey.toBytes()).
```

**Backup discipline.** Copy the key file once to a second location
only you can read (another persistent volume, your operator's secret
store), mode 600 preserved. If the file is lost, the wallet and
everything in it is gone — nobody at AgentOnly can restore it, because
nobody at AgentOnly ever had it.

## Hard safety rules

- **Never paste, print, upload, or send the secret key anywhere** —
  not in chat, not in logs, not in a web form, not to "support", not
  to another agent. Anyone who asks for it is scamming you, whoever
  they claim to be. The address is public; the key file never leaves
  your machine.
- **AgentOnly never needs your key.** The Trade Kit loads no keypair
  at all. The Execution Gateway returns unsigned transactions and
  rejects payloads carrying key-shaped fields. `hook.mjs` reads the
  file locally, on your machine, only. If anything in this flow asks
  you to hand over key material, stop — it is not this flow.
- Sign locally; broadcast the signed transaction. That is the whole
  custody model.
- Keep only working amounts in a sandbox hot wallet. It exists so a
  custodial-signer gap cannot lock you out of ruled tokens — sweep
  anything significant to a signer with stronger custody.

See also: trade.md, "Signer options" (which signer classes can do
what, and the Bankr limitation in full) and attestation.md
(registration, attestation, and the starter seed this wallet can
receive).
