@definity/stake
v0.5.1
Published
Definity staking CLI — deposit SOL directed to a validator you choose (the direct: memo model), from a keypair, a Trezor (--trezor), a Ledger (--ledger), OR build-only (--owner) for offline/hardware/multisig signing, plus liquid-stake and unstake.
Downloads
1,034
Maintainers
Readme
definity-stake
A command-line staking tool for Definity — for treasuries, validators, and scripts that stake from a keypair instead of a browser.
Its point of difference over the generic spl-stake-pool CLI is direct staking: a deposit that routes pool stake onto a validator you choose, then earns up to 3.5× matching on top. That works by attaching a direct:<validatorVote> memo to the deposit — something no off-the-shelf stake-pool CLI does — so this is the only tool that can direct-stake into the definSOL pool.
It builds the exact transaction the definity.finance direct-stake widget builds (create-ATA + Sanctum DepositSol + the direct: memo), signed by your local keypair. Deposits are permissionless and zero-fee on the pool.
Install
Published on npm as @definity/stake. Requires Node ≥ 18.
Run it without installing anything:
npx @definity/stake --helpOr install it globally to get a definity-stake command on your PATH:
npm install -g @definity/stake
definity-stake --helpgit clone https://github.com/esterhuizen/definity-stake-cli.git
cd definity-stake-cli && npm install
./bin/definity-stake.mjs --help # or `npm link` → then `definity-stake …`Usage
The command is definity-stake when installed globally, or npx @definity/stake without installing — identical otherwise.
definity-stake <command> [options]
Commands:
direct-stake --validator <vote> --amount <SOL> deposit, directed to a validator (+ up to 3.5× matching)
stake --amount <SOL> plain liquid-stake (definSOL, no direction)
unstake --amount <definSOL> redeem some definSOL → SOL (Jupiter, redeems at ~NAV)
unstake-all redeem your ENTIRE definSOL balance → SOL (no dust)
balance [--wallet <addr> | --trezor|--ledger] definSOL held + directed positions
validators [--query <text>] list Definity's vetted validator set
Options:
--keypair <path> signer (default: $SOLANA_KEYPAIR or ~/.config/solana/id.json)
--trezor sign on a Trezor (in-CLI; needs @definity/stake-trezor — see below)
--trezor-path <p> derivation path for --trezor (default: m/44'/501'/0'/0')
--ledger sign on a Ledger (in-CLI; needs @definity/stake-ledger — see below)
--ledger-path <p> derivation path for --ledger (default: 44'/501'/0')
--rpc <url> RPC endpoint (default: $SOLANA_RPC or mainnet-beta)
--broadcast actually sign & send (default: simulate only)Safe by default. Every command simulates the transaction and prints the result. Add --broadcast to sign and send for real.
Treasuries, hardware wallets & multisig (offline signing)
For a treasury you should never hand a raw key to a CLI. Pass --owner <pubkey> instead of a keypair and direct-stake runs in build-only mode: no private key is loaded, and it prints a full decode plus an unsigned, serialized transaction (base64) for you to verify and sign offline (air-gapped signer or Squads multisig). Ledger and Trezor owners don't need this any more — they sign in-CLI with --ledger / --trezor, see below.
definity-stake direct-stake \
--validator <validatorVote> --amount 1 \
--owner <yourTreasuryPubkey>It emits:
- a human-readable decode — fee payer/owner, amount, the definSOL recipient ATA, the exact
direct:<vote>memo, the recent blockhash, and each instruction (create-ATA · SanctumDepositSolix 14 · memo); - a simulation of the unsigned transaction (
sigVerifyoff) so you can see it lands before signing; - the base64 unsigned transaction, which you can independently decode to confirm the accounts, amount and memo, then sign offline and broadcast.
The instruction set is byte-identical to the signed path (both build from the same code), so what you verify is what executes. The recent blockhash expires in ~60–90s — refresh it in your signer if needed, or build fully offline with --blockhash <hash> (skips the RPC fetch and simulation).
Trezor (sign in-CLI, key never leaves the device)
Trezor tooling cannot ingest an externally built unsigned transaction, so the build-only flow above doesn't work for Trezor users. Instead, pass --trezor and the CLI signs on the device directly — for direct-stake, stake, unstake and unstake-all (and balance derives the device's wallet).
Trezor support lives in an opt-in companion package (the official Trezor Connect stack is large — keeping it out of the base preserves this CLI's minimal dependency tree):
npm install -g @definity/stake @definity/stake-trezor
definity-stake direct-stake --validator <validatorVote> --amount 1 --trezor --broadcastWithout the companion installed, --trezor fails immediately with the install hint — nothing else changes.
Supported devices. Model T and Safe 3 (firmware ≥ 2.6.4), Safe 5 / Safe 7 (native). Model One does not support Solana.
Prerequisites.
- Trezor Suite or Trezor Bridge running, or on Linux the Trezor udev rules for direct USB access.
- Device connected and unlocked. The first call may prompt for PIN/passphrase on the device.
How it works.
- The Solana account is derived at
m/44'/501'/0'/0'by default; pick another account with--trezor-path "m/44'/501'/1'/0'". The CLI prints the derived address before doing anything — check it is the wallet you expect. - The derived address is the fee payer and definSOL recipient; the
direct:<vote>memo is attached automatically, exactly as in every other mode. - Verify-before-sign: for
direct-stakeandstakethe full instruction decode and an unsigned simulation are printed before the device prompts.unstake/unstake-allsign a Jupiter-built swap transaction — the CLI cannot decode it instruction-by-instruction, so instead it binds it to your derived address (fee payer must match, exactly one signature), simulates it unsigned, and aborts on any failure before the device is woken. - Without
--broadcastno signing is ever requested — the device is only contacted to derive your address (which may ask for PIN/passphrase on the device), then you get the decode + simulation and the CLI exits. - The blockhash is fetched immediately before the device prompt (on-device confirmation is slow). If it expires while you're confirming, the CLI rebuilds with a fresh one and asks you to confirm once more — the decode does not change.
- No secret ever exists on the host, and Trezor Connect payloads are never logged.
Manual hardware test plan (run once per release with a device):
Fresh registry install:
npm i -g @definity/stake @definity/stake-trezor, thennpm ls -g protobufjs— every copy must be the patched version from the companion's shrinkwrap (dependency shrinkwraps are honored on registry installs, not local-tarball ones, so this is only checkable post-publish).definity-stake direct-stake --validator <vote> --amount 0.001 --trezor— confirm the derived address is printed, the 3-instruction decode is shown, the simulation passes, and no signing prompt appears on the device (it is only touched to derive the address).Re-run with
--broadcast— the device renders the create-ATA anddirect:<vote>memo instructions readably, but shows the SanctumDepositSolas an unrecognized-instruction summary (its firmware does not decode this program): verify the memo text and owner address on the device screen against the CLI decode, approve, and note the signature the CLI prints.Open the signature on
solscan.io— confirm theDepositSolinto poolBvbu55…MmPLand thedirect:<vote>memo are both present, and definSOL arrived at the derived address's ATA.definity-stake balance --wallet <derivedAddress>— the directed position appears once the indexer picks up the memo (≤ ~10 min).
Ledger (sign in-CLI)
Same opt-in companion pattern as Trezor — the @ledgerhq stack lives in its own package:
npm install -g @definity/stake @definity/stake-ledger
definity-stake direct-stake --validator <validatorVote> --amount 1 --ledger --broadcastPrerequisites. Ledger connected and unlocked with a recent Solana app open (update via Ledger Live), and blind signing enabled (Solana app → Settings → Allow blind sign — the deposit uses a custom program instruction the app cannot decode). The CLI checks the blind-signing state during setup and tells you exactly what to enable, before any prompt; if the app is too old to report it, the refusal at signing time is translated to the same instruction. On Linux, the Ledger udev rules.
Derivation paths. Defaults to 44'/501'/0' (account 0; m/ prefix optional, indexes auto-hardened). Path conventions vary across tools — solana-cli's usb://ledger uses the bare 44'/501' root, wallets typically use 44'/501'/N' — so the CLI prints the derived address before doing anything: check it is the wallet you expect, and use --ledger-path to select another account. Verify-before-sign, fresh-blockhash, and the never-resign-after-send invariant behave exactly as in the Trezor section.
Manual hardware test plan (run once per release with a device): same four steps as the Trezor plan above, substituting --ledger; on step 2 expect the device to show the transaction as unverifiable/blind-signed data (the Solana app cannot decode the deposit instruction) — the CLI decode printed before the prompt is the verification.
Reproducibility. Dependencies are pinned to exact versions and an
npm-shrinkwrap.jsonis committed and shipped with each package, so installs resolve the exact tested versions. One honest caveat: the Ledger companion's tree contains native modules (node-hid,usb) that fetch prebuilt binaries or compile from source at install time — the shrinkwrap pins their versions, not the binary artifacts, so those two packages are not byte-identical across platforms. The base CLI stays minimal (~75 packages); the Trezor stack lives in@definity/stake-trezor(its own shrinkwrap pins the full Connect tree, includingprotobufjsoverridden to a patched version — an override a plain lockfile would NOT propagate to installs). Each release is a git tag — build from the tag for a verifiable, reproducible install.
Examples
# Find a validator to back (filter the vetted set by name, city, or country)
definity-stake validators --query <name-or-city>
# Dry-run a 1 SOL direct stake (simulates, no funds move)
definity-stake direct-stake \
--validator <validatorVote> --amount 1
# Send it
definity-stake direct-stake \
--validator <validatorVote> --amount 1 --broadcast
# Hardware wallet: sign in-CLI on the device (companion package required, see above)
definity-stake direct-stake --validator <validatorVote> --amount 1 --ledger --broadcast
definity-stake direct-stake --validator <validatorVote> --amount 1 --trezor --broadcast
# Treasury: build an UNSIGNED tx to verify + sign offline (no key loaded)
definity-stake direct-stake \
--validator <validatorVote> --amount 1 --owner <treasuryPubkey>
# Check what you hold + what's directed
definity-stake balance
# Exit: redeem 5 definSOL back to SOL
definity-stake unstake --amount 5 --broadcast
# Full exit: redeem your entire definSOL balance (exact, no dust left over)
definity-stake unstake-all --broadcastHow direct staking settles
- Your deposit mints definSOL to your wallet and carries the
direct:<vote>memo. - Definity's optimiser reads the memo and directs your 1× principal onto that validator at the next cycle.
- Once the deposit has been held a full epoch, up to 3.5× matching is added on top — up to 4.5× total, capped at 20,000 SOL/validator.
- To exit,
unstakeswaps your definSOL back to SOL (redeems at ~NAV; the directed stake unwinds with your holdings).
Your funds and definSOL stay in your wallet the whole time — Definity never custodies them.
Pool facts
- Pool:
Bvbu55B991evqqhLtKcyTZjzQ4EQzRUwtf9T4CcpMmPL(SanctumSanctumSplMulti, programSPMBzs…) - definSOL mint:
DEF1NXSZ8Th9n28hYBayrFtx9bj1EwwTiy3mhHEB9oyA DepositSolis permissionless and currently zero-fee.
Prototype. Simulate first; you are responsible for your keys and transactions.
