TrenchyToolsAPI

Wallet backups

The rule every app on this API follows: a wallet is written to disk, in a place you can find, before it holds anything.

The API never sees your keys, which means it can never give one back. Bots create wallets constantly — funding wallets, bundle wallets, per-coin wallets, vanity mints — and the most common way money is lost is a key that only ever existed in memory, in a log line, or in a terminal that was closed. So this is a rule, enforced in AGENTS.md and in every prompt we publish, not a tip.

Before a wallet is funded, its secret is on disk, and the path has been printed. An app that cannot show where a key is saved must not send to that wallet.

The pattern

  1. One file per wallet

    wallets/<label>-<address>.json next to the project: { "address", "secretKey" (base58 or hex), "chain", "label", "createdAt" }. Append-only; never overwrite an existing file.

  2. Print the path

    Log the absolute path the moment the file is written, before anything else happens with that wallet.

  3. Gate funding on it

    The funding step reads the file back (not the in-memory key) and refuses if it is missing.

  4. Export on demand

    A command (npm run export-wallets) that writes one plain-text file with every address and secret to the user's Desktop, for a password manager or an offline copy. Tell the user to run it after every session that created wallets.

  5. Encrypt at rest when the app is shared

    For a hosted app or a shared machine, AES-256-GCM with a key from ENCRYPTION_KEY; keep the plain export as the user's own responsibility.

JavaScript
import fs from 'node:fs'
import path from 'node:path'
import bs58 from 'bs58'
import { Keypair } from '@solana/web3.js'

const DIR = path.resolve('wallets')

export function newWallet(label) {
  const kp = Keypair.generate()
  const file = path.join(DIR, `${label}-${kp.publicKey.toBase58()}.json`)
  fs.mkdirSync(DIR, { recursive: true })
  fs.writeFileSync(file, JSON.stringify({ address: kp.publicKey.toBase58(), secretKey: bs58.encode(kp.secretKey), chain: 'sol', label, createdAt: new Date().toISOString() }, null, 2), { flag: 'wx' })
  console.log(`wallet saved → ${file}`)   // before the wallet is used for anything
  return kp
}

export function assertBackedUp(address) {
  const ok = fs.readdirSync(DIR).some((f) => f.endsWith(`-${address}.json`))
  if (!ok) throw new Error(`refusing to fund ${address}: no backup in ${DIR}`)
}

What the API does on its side

  • GET /api/create-wallet and the vanity endpoints return a backup object (what to save, a checklist) next to the keys, and show the secret once.
  • The docs key creator offers "Download as .txt" and never stores a key.
  • Transfers and trades are built for addresses you give; the API cannot recover a wallet it never had.
Treat .env and wallets/ as secrets: .gitignore them, never paste them into chat with an assistant, never into a public repo.