Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ jup predictions positions

> [!NOTE]
> This CLI is designed to be LLM friendly and **all commands are non-interactive**. Set JSON output mode globally for structured responses: `jup config set --output json`, or use `-f json` flag on individual commands.
>
> Use `--dry-run` on any transacting command to preview the result without signing or submitting on-chain. In JSON mode, the response includes the unsigned base64 `transaction` for external signing.

[Read the docs](./docs/) for specific guides, examples, and workflows:

Expand Down
4 changes: 4 additions & 0 deletions docs/lend.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ jup lend earn positions --token USDC
jup lend earn deposit --token USDC --amount 100
jup lend earn deposit --token SOL --amount 1.5 --key mykey
jup lend earn deposit --token USDC --raw-amount 100000000
jup lend earn deposit --token USDC --amount 100 --dry-run
```

- `--token` (required) — underlying token to deposit (symbol or mint address)
- `--amount` uses human-readable units (e.g. `100` USDC = 100 USDC)
- `--raw-amount` uses on-chain units (e.g. `100000000` = 100 USDC)
- Exactly one of `--amount` or `--raw-amount` is required
- `--key` overrides the active key for this transaction
- `--dry-run` previews the deposit without signing. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response:
Expand All @@ -94,13 +96,15 @@ jup lend earn withdraw --token USDC --amount 50
jup lend earn withdraw --token USDC # withdraw entire position
jup lend earn withdraw --token jlUSDC --amount 50 # also accepts jlToken directly
jup lend earn withdraw --token USDC --raw-amount 50000000
jup lend earn withdraw --token USDC --amount 50 --dry-run
```

- `--token` (required) — token to withdraw (accepts underlying symbol/address or jlToken symbol/address)
- `--amount` in human-readable units of the underlying token
- `--raw-amount` in on-chain units of the jlToken
- When neither `--amount` nor `--raw-amount` is provided, withdraws the entire position
- `--key` overrides the active key for this transaction
- `--dry-run` previews the withdrawal without signing. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response:
Expand Down
12 changes: 12 additions & 0 deletions docs/perps.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,16 @@ jup perps open --asset ETH --side long --amount 10 --input USDC --leverage 3 --t

# Limit order (triggers when price reaches --limit)
jup perps open --asset BTC --side long --amount 10 --input USDC --leverage 2 --limit 65000

# Dry-run to preview without executing
jup perps open --asset SOL --side long --amount 0.2 --leverage 2 --dry-run
```

- `--side` accepts `long`, `short`, `buy` (= long), or `sell` (= short)
- `--input` defaults to SOL; accepts SOL, BTC, ETH, or USDC
- `--slippage` defaults to 200 (2%); set in basis points
- `--tp` and `--sl` cannot be combined with `--limit`
- `--dry-run` previews the order without signing. The API simulates the transaction, returning entry price, size, leverage, liquidation price, and fees. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response (market order):
Expand Down Expand Up @@ -188,9 +192,13 @@ jup perps set --position <pubkey> --tp 100 --sl 70

# Update a limit order's trigger price
jup perps set --order <pubkey> --limit 64000

# Dry-run
jup perps set --position <pubkey> --tp 100 --sl 70 --dry-run
```

- Get the `positionPubkey` or `orderPubkey` from `jup perps positions`
- `--dry-run` previews the update without signing. JSON response includes the unsigned base64 `transaction` for each update.

```js
// Example JSON response (update limit order):
Expand Down Expand Up @@ -240,10 +248,14 @@ jup perps close --order <pubkey>

# Cancel a TP/SL order
jup perps close --tpsl <pubkey>

# Dry-run
jup perps close --position <pubkey> --dry-run
```

- `--receive` defaults to the position's collateral token; must be USDC or the market token (e.g. BTC for a BTC position)
- `--size` for partial close; omit to close entirely
- `--dry-run` previews the close without signing, showing PnL, fees, and received amount. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response (close/decrease position):
Expand Down
6 changes: 6 additions & 0 deletions docs/predictions.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,14 @@ jup predictions positions --position <pubkey>
jup predictions open --market <marketId> --side yes --amount 10
jup predictions open --market <marketId> --side no --amount 5 --input USDC
jup predictions open --market <marketId> --side y --amount 10 --key mykey
jup predictions open --market <marketId> --side yes --amount 10 --dry-run
```

- `--market`: market ID from `jup predictions events`
- `--side`: `yes`, `no`, `y`, `n`
- `--amount`: input token amount (human-readable)
- `--input`: input token symbol or mint (default: `USDC`)
- `--dry-run` previews the order without signing, showing cost, fees, and payout. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response:
Expand Down Expand Up @@ -123,11 +125,15 @@ jup predictions close --position <pubkey>

# Close all positions
jup predictions close --position all

# Dry-run
jup predictions close --position <pubkey> --dry-run
```

- The CLI auto-detects whether to sell or claim based on the market result
- Claimable positions (market resolved in your favor) are claimed for the full payout
- Open positions on live markets are sold at the current market price
- `--dry-run` previews the close without signing. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response (close):
Expand Down
12 changes: 9 additions & 3 deletions docs/spot.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ jup spot quote --from <mint> --to <mint> --raw-amount 1000000000
jup spot swap --from SOL --to USDC --amount 1
jup spot swap --from SOL --to USDC --amount 1 --key mykey
jup spot swap --from SOL --to USDC --amount 1 --slippage 50
jup spot swap --from SOL --to USDC --amount 1 --dry-run
```

- `--key` overrides the active key for this transaction
- `--slippage` sets max slippage in basis points (e.g. `50` = 0.5%). Recommended to be emtpy: Jupiter's Real-Time Slippage Estimation (RTSE) automatically picks an optimal value.
- `--dry-run` previews the swap without signing or submitting. The API still simulates the transaction, so errors like insufficient balance are caught. In JSON mode, the response includes the unsigned base64 `transaction` for external signing.

```js
// Example JSON response:
Expand Down Expand Up @@ -113,9 +115,11 @@ jup spot portfolio --address <wallet-address>
jup spot reclaim
jup spot reclaim --key mykey
jup spot reclaim --token USDC
jup spot reclaim --dry-run
```

- With no options, reclaims rent from all empty Associated Token Accounts (ATA) owned by the active key's wallet
- `--dry-run` previews reclaimable amount without executing. JSON response includes the unsigned base64 `transactions` array.

```js
// Example JSON response:
Expand Down Expand Up @@ -171,10 +175,12 @@ jup spot transfer --token SOL --to <recipient-address> --amount 1
jup spot transfer --token USDC --to <recipient-address> --amount 50
jup spot transfer --token <mint> --to <recipient-address> --raw-amount 1000000000
jup spot transfer --token SOL --to <recipient-address> --amount 1 --key mykey
jup spot transfer --token SOL --to <recipient-address> --amount 1 --dry-run
```

- Works with both SOL and any SPL token
- `--token` accepts a symbol or mint address
- `--dry-run` previews the transfer without signing. JSON response includes the unsigned base64 `transaction`.

```js
// Example JSON response:
Expand All @@ -191,11 +197,11 @@ jup spot transfer --token SOL --to <recipient-address> --amount 1 --key mykey

## Workflows

### Check price then swap
### Dry-run then swap

```bash
jup spot quote --from SOL --to USDC --amount 1
# Review the quoted output and price impact
jup spot swap --from SOL --to USDC --amount 1 --dry-run
# Review the output, fees, and simulation result
jup spot swap --from SOL --to USDC --amount 1
```

Expand Down
84 changes: 78 additions & 6 deletions src/commands/LendCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,47 @@ export class LendCommand {
rawAmount: opts.rawAmount,
});

const apyPct = this.rateToPct(lendToken.totalRate);

if (Config.dryRun) {
if (Output.isJson()) {
Output.json({
dryRun: true,
token: {
id: lendToken.assetAddress,
symbol: lendToken.asset.symbol,
decimals: lendToken.asset.decimals,
},
depositedAmount: swap.inAmount,
depositedUsd: swap.order.inUsdValue,
apyPct,
signature: null,
transaction: swap.order.transaction,
});
return;
}

console.log(Output.DRY_RUN_LABEL);
Output.table({
type: "vertical",
rows: [
{
label: "Deposited",
value: `${swap.inAmount} ${lendToken.asset.symbol} (${Output.formatDollar(swap.order.inUsdValue)})`,
},
{
label: "APY",
value: Output.formatPercentageChange(apyPct),
},
],
});
return;
}

const { positionAmount, price } = await this.fetchCurrentPosition(
signer.address,
lendToken
);
const apyPct = this.rateToPct(lendToken.totalRate);

if (Output.isJson()) {
Output.json({
Expand All @@ -254,7 +290,7 @@ export class LendCommand {
positionAmount,
positionUsd: positionAmount * price,
apyPct,
signature: swap.result.signature,
signature: swap.result!.signature,
});
return;
}
Expand All @@ -276,7 +312,7 @@ export class LendCommand {
},
{
label: "Tx Signature",
value: swap.result.signature,
value: swap.result!.signature,
},
],
});
Expand Down Expand Up @@ -336,11 +372,47 @@ export class LendCommand {
rawAmount,
});

const apyPct = this.rateToPct(lendToken.totalRate);

if (Config.dryRun) {
if (Output.isJson()) {
Output.json({
dryRun: true,
token: {
id: lendToken.assetAddress,
symbol: lendToken.asset.symbol,
decimals: lendToken.asset.decimals,
},
withdrawnAmount: swap.outAmount,
withdrawnUsd: swap.order.outUsdValue,
apyPct,
signature: null,
transaction: swap.order.transaction,
});
return;
}

console.log(Output.DRY_RUN_LABEL);
Output.table({
type: "vertical",
rows: [
{
label: "Withdrawn",
value: `${swap.outAmount} ${lendToken.asset.symbol} (${Output.formatDollar(swap.order.outUsdValue)})`,
},
{
label: "APY",
value: Output.formatPercentageChange(apyPct),
},
],
});
return;
}

const { positionAmount, price } = await this.fetchCurrentPosition(
signer.address,
lendToken
);
const apyPct = this.rateToPct(lendToken.totalRate);

if (Output.isJson()) {
Output.json({
Expand All @@ -354,7 +426,7 @@ export class LendCommand {
positionAmount,
positionUsd: positionAmount * price,
apyPct,
signature: swap.result.signature,
signature: swap.result!.signature,
});
return;
}
Expand All @@ -376,7 +448,7 @@ export class LendCommand {
},
{
label: "Tx Signature",
value: swap.result.signature,
value: swap.result!.signature,
},
],
});
Expand Down
Loading
Loading