> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voltr.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI & Scripts

> Operate Voltr vaults and every strategy integration from one CLI, plus runnable programmatic examples

All vault operations — setup, deposits/withdrawals, and every supported strategy (Kamino, Spot, Trustful) — now live in a single repository: [**github.com/voltrxyz/sdk-scripts**](https://github.com/voltrxyz/sdk-scripts).

It replaces the old per-protocol script repos (`kamino-scripts`, `spot-scripts`, `trustful-scripts`, `lend-scripts`, `drift-scripts`, `client-raydium-clmm-scripts`) with two complementary entry points:

<CardGroup cols={2}>
  <Card title="CLI" icon="terminal">
    The **recommended** interface for vault managers and operators. Every operation is one `<group>:<action>` command driven by a JSON profile and per-call flags. No source edits to change runtime values.
  </Card>

  <Card title="Programmatic examples" icon="code">
    Runnable TypeScript for developers embedding the operation builders directly in their own services, bots, or transaction pipelines. One self-contained file per action.
  </Card>
</CardGroup>

<Info>
  The CLI and examples both wrap the lower-level [`@voltr/vault-sdk`](/developers/sdk-reference) and the protocol adapter packages. Use the CLI for routine operations; drop down to the SDK or examples when you embed Voltr in your own code.
</Info>

<Tip>
  Driving these operations from a coding agent? The [Voltr Agent Skill](/explore/agent-skill) ships `vault-manager-cli.md` and `vault-manager-sdk.md` references plus runnable `examples/sdk/` flows (create vault, add adaptor + init strategy, allocate, read state).
</Tip>

## Repository layout

| Path                                                      | What it is                                                                                                          |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `apps/cli`                                                | The unified CLI (`@voltr/scripts-cli`) exposing every `<group>:<action>` command                                    |
| `packages/core`                                           | Shared vault behavior — signers, RPC, token accounts, lookup tables, transaction modes (`@voltr/scripts-core`)      |
| `packages/kamino` · `packages/spot` · `packages/trustful` | Per-integration adapter packages (account derivation + instruction building)                                        |
| `examples/`                                               | One runnable TypeScript file per action, for SDK consumers                                                          |
| `docs/`                                                   | Canonical guides: `operator-guide.md`, `kamino.md`, `spot.md`, `trustful.md`, `adaptor-admin.md`, `architecture.md` |

## Install

```bash theme={null}
git clone https://github.com/voltrxyz/sdk-scripts.git
cd sdk-scripts
pnpm install
```

Validate the bundled example profile. This is fully offline — no RPC, no keypair, no deployed vault — and the quickest way to confirm your checkout works:

```bash theme={null}
pnpm cli -- --profile configs/examples/usdc.mainnet.example.json check
```

<Note>
  `pnpm cli -- <args>`: the leading `--` separates pnpm's own arguments from the CLI's. Flags after it (`--profile`, `--mode`, …) are parsed normally.
</Note>

## Profiles

A **profile** is one JSON file describing one vault deployment: its cluster, asset, optional lookup table, and any integration addresses. Routine operational values live in the profile; per-call values are flags; secrets are never in the profile. The profile is validated with zod on load, so a missing or malformed field fails before any RPC call.

```bash theme={null}
# Copy the example and edit it:
cp configs/examples/usdc.mainnet.example.json configs/my-vault.json
#   vault.assetMintAddress / vault.assetTokenProgram  (required)
#   vault.vaultAddress                                (leave empty until vault:init prints it)
#   integrations.<adapter>.*                          (only the adapters you use)
```

```jsonc theme={null}
{
  "name": "my-vault",                       // required, non-empty — use neutral names
  "cluster": "mainnet-beta",                // localnet | devnet | mainnet-beta
  "rpcUrl": "",                             // optional fallback RPC (env/flag override it)
  "vault": {
    "name": "My USDC Vault",                // optional display label
    "assetMintAddress": "<ASSET_MINT>",     // required
    "assetTokenProgram": "<TOKEN_PROGRAM>", // required (Token or Token-2022)
    "vaultAddress": "<VAULT_ADDRESS>",      // generated by vault:init — leave empty until then
    "useLookupTable": false,
    "lookupTableAddress": "<LUT_ADDRESS>"   // required only when useLookupTable is true
  },
  "integrations": {
    "kamino":   { "reserveAddress": "<RESERVE>", "kvaultAddress": "<KVAULT>", "directWithdrawDiscriminator": [/* 8 bytes */] },
    "spot":     { "foreignMintAddress": "<MINT>", "foreignTokenProgram": "<PROG>", "assetOracleAddress": "<ORACLE>", "foreignOracleAddress": "<ORACLE>", "directWithdrawDiscriminator": [/* 8 bytes */] },
    "trustful": { "strategySeedString": "<SEED>" }
  }
}
```

## Keypairs & roles

Commands sign as one of four roles. Each resolves its keypair path from a flag, falling back to an environment variable — **the flag wins**. If neither is set, the command fails up front naming both.

| Role             | Flag                | Env var           | Used by                                                                |
| ---------------- | ------------------- | ----------------- | ---------------------------------------------------------------------- |
| `admin`          | `--admin-keypair`   | `ADMIN_KEYPAIR`   | `vault:init*`, metadata, config, adaptor admin, harvest-fee            |
| `protocol admin` | `--admin-keypair`   | `ADMIN_KEYPAIR`   | protocol treasury/admin changes and per-vault adaptor-policy overrides |
| `manager`        | `--manager-keypair` | `MANAGER_KEYPAIR` | strategy operations (Kamino/Spot/Trustful, claims)                     |
| `user`           | `--user-keypair`    | `USER_KEYPAIR`    | deposit/withdraw, direct-withdraw                                      |

```bash theme={null}
# .env (gitignored) — copy .env.example and set once:
RPC_URL=https://your-rpc
ADMIN_KEYPAIR=/path/to/admin.json
MANAGER_KEYPAIR=/path/to/manager.json
USER_KEYPAIR=/path/to/user.json
```

<Warning>
  No keypair material lives in profiles — only paths, via flag or env. Keep keypair files outside the repo, restrict permissions (`chmod 600`), and prefer env vars over flags so secret paths don't land in shell history. The read-only `*:query:*` commands and `check` need no keypair.
</Warning>

The RPC URL resolves in this order (first non-empty wins): `--rpc-url` flag → `RPC_URL` env → `HELIUS_RPC_URL` env → `rpcUrl` in the profile.

## Transaction modes — verify before you execute

Every transaction command takes `--mode` (default `print`). A command **builds first** (reading chain state over RPC, and the Jupiter API for swaps), then dispatches the mode — so a reachable RPC is required in every mode except `check`.

| Mode                | Sends on-chain? | What it does                                                                                                      |
| ------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------- |
| `print` *(default)* | No              | Prints `{ label, instructionCount, lookupTableAddresses }` + operation metadata. The no-send preview.             |
| `simulate`          | No              | One `simulateTransaction` RPC; prints `OK`/`FAILED`, compute units, program logs, explorer URL.                   |
| `multisig`          | No              | Emits a base64/base58 transaction message to import into a multisig (e.g. Squads). Requires `--multisig-address`. |
| `execute`           | **Yes**         | Signs with the role keypair, sends, confirms; prints the signature and compute units.                             |

<Tip>
  **Never `execute` blind.** Preview with `--mode print`, confirm with `--mode simulate`, then `--mode execute`. For a multisig-controlled vault, use `--mode multisig --multisig-address <VAULT_SIGNER_PDA>` and import the printed payload instead of signing locally.
</Tip>

```bash theme={null}
# 1. print: confirm the plan builds and the instruction/LUT counts look right
pnpm cli -- --profile configs/my-vault.json --mode print    vault:deposit --amount 1000000
# 2. simulate: confirm it would succeed on-chain
pnpm cli -- --profile configs/my-vault.json --mode simulate vault:deposit --amount 1000000
# 3. execute: send it for real
pnpm cli -- --profile configs/my-vault.json --mode execute  vault:deposit --amount 1000000
```

### Global options

| Option                              | Purpose                                                 |
| ----------------------------------- | ------------------------------------------------------- |
| `--profile <path>`                  | Profile JSON to load (required)                         |
| `--rpc-url <url>`                   | RPC override                                            |
| `--mode <mode>`                     | `print` (default) / `simulate` / `multisig` / `execute` |
| `--multisig-address <pubkey>`       | On-chain signer PDA; required for `--mode multisig`     |
| `--priority-fee <kind>`             | `helius` (default) / `rpc` / `fixed` / `none`           |
| `--priority-fee-micro-lamports <n>` | microLamports for `--priority-fee fixed`                |
| `--compute-unit-limit <n>`          | Override the estimated compute-unit limit               |

## Command groups

Commands are grouped by `<group>:*` prefix. The CLI itself is the authoritative reference for the full command surface and every flag:

```bash theme={null}
pnpm cli -- --help                 # global options + all command groups
pnpm cli -- vault:deposit --help   # flags for a single command
```

| Group              | Commands                                                                                                                                                                                                                                                                                                                          | Reference                                                                                     |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| **Vault (core)**   | `vault:init`, `vault:init-and-set-token-metadata`, `vault:set-token-metadata`, `vault:update-config`, `vault:accept-admin`, `vault:harvest-fee`, `vault:deposit`, `vault:request-withdraw`, `vault:withdraw`, `vault:cancel-request-withdraw`, `vault:instant-withdraw`, `vault:query:position`, `vault:query:strategy-positions` | [operator-guide.md](https://github.com/voltrxyz/sdk-scripts/blob/main/docs/operator-guide.md) |
| **Adaptor admin**  | `vault:add-adaptor`, `vault:remove-adaptor`, `vault:init-direct-withdraw`                                                                                                                                                                                                                                                         | [adaptor-admin.md](https://github.com/voltrxyz/sdk-scripts/blob/main/docs/adaptor-admin.md)   |
| **Protocol admin** | `protocol:update-treasury`, `protocol:set-pending-admin`, `protocol:accept-admin`, `vault:update-adaptor-policy`                                                                                                                                                                                                                  | [adaptor-admin.md](https://github.com/voltrxyz/sdk-scripts/blob/main/docs/adaptor-admin.md)   |
| **Kamino**         | `kamino:market:{init,deposit,withdraw,claim-reward}`, `kamino:kvault:{init,deposit,withdraw,claim-reward-with-index,direct-withdraw,request-and-direct-withdraw}`                                                                                                                                                                 | [kamino.md](https://github.com/voltrxyz/sdk-scripts/blob/main/docs/kamino.md)                 |
| **Spot**           | `spot:swap:{init,buy,sell}`, `spot:earn:{init,extend-lut,deposit,withdraw,init-direct-withdraw}`, `spot:query:strategy-positions`                                                                                                                                                                                                 | [spot.md](https://github.com/voltrxyz/sdk-scripts/blob/main/docs/spot.md)                     |
| **Trustful**       | `trustful:arbitrary:{init,deposit,withdraw}`, `trustful:curve:{init,borrow,repay,remove}`                                                                                                                                                                                                                                         | [trustful.md](https://github.com/voltrxyz/sdk-scripts/blob/main/docs/trustful.md)             |
| **Maintenance**    | `check` (offline profile validation)                                                                                                                                                                                                                                                                                              | —                                                                                             |

### Recipes

The following assume `RPC_URL` and the role keypairs are set in `.env`. Run each with `--mode print` then `--mode simulate` before `--mode execute`.

<AccordionGroup>
  <Accordion title="Initialize a vault">
    ```bash theme={null}
    # admin signs; manager is just an address. A fresh vault keypair is generated and its address printed.
    pnpm cli -- --profile configs/my-vault.json --mode execute \
      vault:init --manager <MANAGER_PUBKEY> --name "My USDC Vault" --max-cap 100000000000

    # Record the printed "Generated vault address" as vault.vaultAddress in the profile.

    # (alt) init + LP-token metadata in one transaction:
    pnpm cli -- --profile configs/my-vault.json --mode execute \
      vault:init-and-set-token-metadata --manager <MANAGER_PUBKEY> --name "My USDC Vault" \
      --max-cap 100000000000 --metadata-name "My USDC Vault Token" --metadata-symbol MYUSDC \
      --metadata-uri https://example.com/metadata.json
    ```

    <Note>`vault:init` cannot use `--mode multisig`: a fresh vault keypair must sign initialization, which a multisig payload can't carry. Use `--mode execute`.</Note>
  </Accordion>

  <Accordion title="Add an adapter (one-time admin step)">
    `vault:add-adaptor` defaults to the Kamino adaptor; pass `--adaptor-program` for the others.

    ```bash theme={null}
    # Kamino (default adaptor):
    pnpm cli -- --profile configs/my-vault.json --mode execute vault:add-adaptor
    # Spot:
    pnpm cli -- --profile configs/my-vault.json --mode execute \
      vault:add-adaptor --adaptor-program EW35URAx3LiM13fFK3QxAXfGemHso9HWPixrv7YDY4AM
    # Trustful:
    pnpm cli -- --profile configs/my-vault.json --mode execute \
      vault:add-adaptor --adaptor-program 3pnpK9nrs1R65eMV1wqCXkDkhSgN18xb1G5pgYPwoZjJ

    # Register a direct-withdraw strategy (Kamino kvault default + profile discriminator):
    pnpm cli -- --profile configs/my-vault.json --mode execute vault:init-direct-withdraw
    # Spot Earn uses its own command (derives the strategy for you):
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:earn:init-direct-withdraw
    ```
  </Accordion>

  <Accordion title="Protocol administration and per-vault adaptor policy">
    These operations use the protocol-admin keypair through `--admin-keypair` / `ADMIN_KEYPAIR`, not a vault admin.

    ```bash theme={null}
    # Set the protocol treasury receiving the protocol fee share:
    pnpm cli -- --mode execute protocol:update-treasury --treasury <TREASURY_PUBKEY>

    # Transfer protocol administration: current admin sets, incoming admin accepts:
    pnpm cli -- --mode execute protocol:set-pending-admin --pending-admin <NEW_ADMIN_PUBKEY>
    pnpm cli -- --mode execute protocol:accept-admin

    # Per-vault policy: 0 enforces the allowlist; 1 permits any executable adaptor.
    # Setting 0 does not remove adaptor receipts created while it was 1.
    pnpm cli -- --profile configs/my-vault.json --mode execute \
      vault:update-adaptor-policy --allow-any-adaptor 0
    ```
  </Accordion>

  <Accordion title="Deposit / withdraw (user)">
    ```bash theme={null}
    pnpm cli -- --profile configs/my-vault.json --mode execute vault:deposit --amount 1000000

    # Read-only position check (ignores --mode, no keypair):
    pnpm cli -- --profile configs/my-vault.json vault:query:position --user <USER_PUBKEY>

    # Standard withdraw: request, wait the lock period, then claim:
    pnpm cli -- --profile configs/my-vault.json --mode execute vault:request-withdraw --amount 1000000   # or --all / --in-lp
    pnpm cli -- --profile configs/my-vault.json --mode execute vault:withdraw

    # Instant withdraw against idle assets (no waiting period):
    pnpm cli -- --profile configs/my-vault.json --mode execute vault:instant-withdraw --amount 1000000   # or --all / --in-lp
    ```
  </Accordion>

  <Accordion title="Kamino market & kVault (manager)">
    ```bash theme={null}
    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:market:init
    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:market:deposit  --amount 1000000
    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:market:withdraw --amount 1000000

    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:kvault:init
    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:kvault:deposit  --amount 1000000
    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:kvault:withdraw --amount 1000000

    # Claim one farm reward (omit --swap-amount when the reward mint == asset mint):
    pnpm cli -- --profile configs/my-vault.json --mode execute kamino:market:claim-reward \
      --reward-mint <REWARD_MINT> --farm-state <FARM_STATE> --user-state <USER_STATE> \
      --swap-amount <RAW_REWARD_AMOUNT> --slippage-bps 50
    ```
  </Accordion>

  <Accordion title="Spot swap & Earn (manager)">
    Register the Spot adaptor first.

    ```bash theme={null}
    # Swap strategy: init, then buy (asset→foreign) / sell (foreign→asset)
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:swap:init
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:swap:buy  --amount 1000000 --slippage-bps 50
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:swap:sell --amount 1000000 --slippage-bps 50

    # Jupiter Earn: init (then extend-lut if you use a LUT), deposit, withdraw
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:earn:init
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:earn:extend-lut
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:earn:deposit  --amount 1000000
    pnpm cli -- --profile configs/my-vault.json --mode execute spot:earn:withdraw --amount 1000000
    ```
  </Accordion>

  <Accordion title="Trustful arbitrary & curve (manager)">
    Register the Trustful adaptor first.

    ```bash theme={null}
    # Arbitrary strategy (deposit prints the withdrawal-holding account — return assets there before withdrawing):
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:arbitrary:init
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:arbitrary:deposit \
      --amount 1000000 --destination <DESTINATION_TOKEN_ACCOUNT> --position-value-after 1000000
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:arbitrary:withdraw \
      --amount 1000000 --position-value-after 0

    # Curve strategy: init, borrow, repay, remove
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:curve:init
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:curve:borrow --amount 1000000 --borrow-rate-bps 50
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:curve:repay  --amount 1000000 --borrow-rate-bps 50
    pnpm cli -- --profile configs/my-vault.json --mode execute trustful:curve:remove
    ```
  </Accordion>
</AccordionGroup>

## Programmatic examples

For automation, bots, and services that embed Voltr directly, the [`examples/`](https://github.com/voltrxyz/sdk-scripts/tree/main/examples) directory holds runnable TypeScript — one self-contained file per action that imports the public operation builders, inspects a `BuiltOperation`, and routes it through the shared transaction processor. They are the lower-level programmatic path; the CLI remains the primary interface for routine operations.

```bash theme={null}
# Configure via env (the examples read the same profile + RPC precedence as the CLI):
export VOLTR_PROFILE=configs/my-vault.json   # default if unset
export RPC_URL=https://your-rpc
export MANAGER_KEYPAIR=/path/to/manager.json # and/or ADMIN_KEYPAIR / USER_KEYPAIR

# List every example with its group, role, and network requirement:
pnpm examples:list

# Run a file directly (no arguments — config comes from env):
pnpm exec tsx examples/src/kamino/market-withdraw.ts

# …or by name through the dispatcher:
pnpm example -- kamino:market-withdraw
```

Per-run values (amounts, rates) are clearly marked constants at the top of each file. Every setting has both an env var and an equivalent flag (`--profile`, `--rpc-url`, `--mode`, `--multisig-address`, `--yes`); `--help` lists them.

<Warning>
  Examples default to `print` and never send. `execute` is **gated** — type `yes` at the prompt, or set `VOLTR_CONFIRM=1` for non-interactive runs. No secrets are committed: addresses come from your profile, keypairs from env vars.
</Warning>

### Example catalog

| Group            | Files                                                                                                                                                |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Vault / core** | `initialize`, `deposit`, `request-withdraw`, `withdraw`, `instant-withdraw`, `cancel-request-withdraw`, `query-position`, `query-strategy-positions` |
| **Kamino**       | `market-{init,deposit,withdraw,claim-reward}`, `kvault-{init,deposit,withdraw,claim-reward,direct-withdraw,request-and-direct-withdraw}`             |
| **Spot**         | `swap-{init,buy,sell}`, `earn-{init,deposit,withdraw,extend-lut,init-direct-withdraw}`, `query-strategy-positions`                                   |
| **Trustful**     | `arbitrary-{init,deposit,withdraw}`, `curve-{init,borrow,repay,remove}`                                                                              |
| **Composition**  | `allocate` — sequence builders from more than one package through the shared processor                                                               |

Examples import only documented package exports (`@voltr/scripts-core`, `@voltr/scripts-kamino`, `@voltr/scripts-spot`, `@voltr/scripts-trustful`). See [examples/README.md](https://github.com/voltrxyz/sdk-scripts/blob/main/examples/README.md) for the full catalog and the offline `pnpm examples:check` verification.

## Where to go next

<CardGroup cols={2}>
  <Card title="Supported Integrations" icon="puzzle-piece" href="/vault-owners/strategies/integrations">
    The adaptors and their CLI command groups
  </Card>

  <Card title="Strategy Setup Guide" icon="route" href="/vault-owners/strategies/setup-guide">
    Add adaptors and initialize strategies
  </Card>

  <Card title="Fund Allocation" icon="arrows-left-right" href="/vault-owners/allocation/overview">
    Deploy idle funds into strategies
  </Card>

  <Card title="SDK Reference" icon="book" href="/developers/sdk-reference">
    The lower-level `@voltr/vault-sdk` builders
  </Card>
</CardGroup>
