@lightspeed-cli/speed-cli 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example ADDED
@@ -0,0 +1,11 @@
1
+ # Required: wallet (hex, with or without 0x prefix)
2
+ PRIVATE_KEY=
3
+
4
+ # 0x Swap API (https://dashboard.0x.org/)
5
+ 0X_API_KEY=
6
+
7
+ # Squid Router (https://docs.squidrouter.com)
8
+ SQUID_INTEGRATOR_ID=
9
+
10
+ # RPC + history (https://dashboard.alchemy.com/)
11
+ ALCHEMY_API_KEY=
package/README.md CHANGED
@@ -17,27 +17,16 @@ npx @lightspeed-cli/speed-cli whoami
17
17
  npx @lightspeed-cli/speed-cli balance --json
18
18
  ```
19
19
 
20
- **First-time setup:** Run `speed setup` to configure `~/.speed/.env` (private key, 0x API key, etc.). See `.env.example` for required vars.
20
+ **First-time setup:** Run `speed setup` to configure `~/.speed/.env`. You’ll need:
21
21
 
22
- ## Publish this package to npm
22
+ | What | Used for | Get it |
23
+ |------|----------|--------|
24
+ | **Alchemy API key** | RPC (Ethereum, Base, OP, Arbitrum, Polygon, BNB) | [alchemy.com](https://www.alchemy.com/) → Create app, copy API key |
25
+ | **0x API key** | Swaps (quote + execute) | [0x.org](https://0x.org/) → Dashboard, create app, API key |
26
+ | **Squid integrator ID** | Bridging across chains | [Squid integrator form](https://squidrouter.typeform.com/integrator-id) |
23
27
 
24
- 1. **Log in to npm** (one-time):
25
- ```bash
26
- npm login
27
- ```
28
- Use your npm account; create one at [npmjs.com](https://www.npmjs.com/signup) if needed.
28
+ See `.env.example` for variable names, or run `speed setup --help`.
29
29
 
30
- 2. **Build and publish** (scoped packages require `--access public`):
31
- ```bash
32
- npm run build
33
- npm publish --access public
34
- ```
35
-
36
- 3. **After publishing**, anyone can install and use the `speed` command:
37
- ```bash
38
- npm install -g @lightspeed-cli/speed-cli
39
- speed --help
40
- ```
41
30
 
42
31
  ## Develop locally
43
32
 
@@ -49,3 +38,4 @@ node dist/cli.js --help
49
38
  npm link
50
39
  speed whoami
51
40
  ```
41
+ **Shell note:** Examples use `||` for "or" (Bash). On PowerShell use `;` instead of `||` to chain commands.
package/dist/cli.js CHANGED
@@ -28,7 +28,7 @@ const program = new Command();
28
28
  program
29
29
  .name("speed")
30
30
  .description("Speed Token CLI: swap, bridge, balance, price, volume, dca, gas, history, xp, and more. Default token is Speed.")
31
- .version("0.1.2")
31
+ .version("0.1.4")
32
32
  .option("-y, --yes", "Skip confirmation for swap/bridge (safe for scripts)")
33
33
  .option("--json", "Output machine-readable JSON to stdout (for scripts and OpenClaw)");
34
34
  program.addCommand(whoamiCmd());
@@ -25,7 +25,7 @@ async function getBalancesForChain(chainId, address, extraTokenAddresses) {
25
25
  address: SPEED_TOKEN_ADDRESS,
26
26
  symbol: speedSymbol,
27
27
  balance: ethers.formatUnits(speedBal, speedDecimals),
28
- decimals: speedDecimals,
28
+ decimals: Number(speedDecimals),
29
29
  },
30
30
  ];
31
31
  const extraAddrs = extraTokenAddresses
@@ -38,7 +38,7 @@ async function getBalancesForChain(chainId, address, extraTokenAddresses) {
38
38
  token.symbol().catch(() => "???"),
39
39
  token.balanceOf(address),
40
40
  ]);
41
- return { address: a, symbol: sym, balance: ethers.formatUnits(bal, dec), decimals: dec };
41
+ return { address: a, symbol: sym, balance: ethers.formatUnits(bal, dec), decimals: Number(dec) };
42
42
  }));
43
43
  for (let i = 0; i < extraResults.length; i++) {
44
44
  const result = extraResults[i];
@@ -136,6 +136,9 @@ export function bridgeCmd() {
136
136
  }
137
137
  catch (e) {
138
138
  const msg = e instanceof Error ? e.message : String(e);
139
+ if (msg.includes("429")) {
140
+ exitWithError(`Squid API rate limit. Wait a minute and try again, or bridge one chain at a time.${usageHint("bridge")}`, "BRIDGE_ERROR");
141
+ }
139
142
  exitWithError(`${msg}.${usageHint("bridge")}`, "BRIDGE_ERROR");
140
143
  }
141
144
  });
@@ -55,13 +55,15 @@ export function configCmd() {
55
55
  setJsonMode(this.parent?.parent?.opts().json ?? false);
56
56
  const config = loadConfig();
57
57
  if (key) {
58
- const v = key === "default-chain" ? config.defaultChain : key === "default-slippage" ? config.defaultSlippage : key === "output-format" ? config.outputFormat : undefined;
59
- if (v === undefined)
58
+ const validKeys = ["default-chain", "default-slippage", "output-format"];
59
+ if (!validKeys.includes(key)) {
60
60
  exitWithError(`Unknown key: ${key}. Valid keys: default-chain, default-slippage, output-format. Example: speed config get default-chain`, "INVALID_KEY");
61
+ }
62
+ const v = key === "default-chain" ? config.defaultChain : key === "default-slippage" ? config.defaultSlippage : config.outputFormat;
61
63
  if (isJsonMode())
62
- out({ [key]: v });
64
+ out({ [key]: v ?? null });
63
65
  else
64
- out(String(v));
66
+ out(v !== undefined && v !== null ? String(v) : "(not set)");
65
67
  }
66
68
  else {
67
69
  if (isJsonMode())
@@ -4,7 +4,7 @@ import { getSigner } from "../wallet.js";
4
4
  import { get0xQuote } from "../lib/zerox.js";
5
5
  import { parseTokenAmountToWei } from "../lib/parse-amount.js";
6
6
  import { getEthUsdPriceNumber } from "../lib/oracle.js";
7
- import { resolveChainId, getChainOptionsHint } from "../constants.js";
7
+ import { resolveChainId, getChainOptionsHint, SPEED_TOKEN_ADDRESS, NATIVE_ETH_0X } from "../constants.js";
8
8
  import { getDefaultChainInput } from "./config.js";
9
9
  import { out, exitWithError, setJsonMode, isJsonMode, usageHint } from "../output.js";
10
10
  export function estimateCmd() {
@@ -30,9 +30,23 @@ export function estimateCmd() {
30
30
  gasLimit = 350000n;
31
31
  }
32
32
  else if (opts.buy && opts.amount) {
33
- const sellToken = opts.sell?.trim() ?? "0xB01CF1bE9568f09449382a47Cd5bF58e2A9D5922";
33
+ const toToken = (v, d) => {
34
+ if (!v)
35
+ return d;
36
+ const t = v.trim().toLowerCase();
37
+ if (t === "speed")
38
+ return SPEED_TOKEN_ADDRESS;
39
+ if (t === "eth" || t === "ether" || t === "native")
40
+ return NATIVE_ETH_0X;
41
+ return v.trim();
42
+ };
43
+ const sellToken = toToken(opts.sell, NATIVE_ETH_0X);
44
+ const buyToken = toToken(opts.buy, SPEED_TOKEN_ADDRESS);
45
+ if (sellToken.toLowerCase() === buyToken.toLowerCase()) {
46
+ exitWithError("Sell and buy tokens must be different. To buy Speed with ETH use --sell eth.", "SAME_TOKEN");
47
+ }
34
48
  const amountWei = parseTokenAmountToWei(opts.amount.trim());
35
- const quote = await get0xQuote(chainId, sellToken, opts.buy.trim(), amountWei, taker);
49
+ const quote = await get0xQuote(chainId, sellToken, buyToken, amountWei, taker);
36
50
  if (quote.gas)
37
51
  gasLimit = BigInt(quote.gas);
38
52
  }
@@ -41,7 +55,8 @@ export function estimateCmd() {
41
55
  const gasWei = gasLimit * gasPrice;
42
56
  const gasEth = ethers.formatEther(gasWei);
43
57
  const ethUsd = await getEthUsdPriceNumber(chainId);
44
- const gasUsd = (parseFloat(gasEth) * ethUsd).toFixed(2);
58
+ const gasUsdNum = parseFloat(gasEth) * ethUsd;
59
+ const gasUsd = gasUsdNum > 0 && gasUsdNum < 0.01 ? gasUsdNum.toFixed(4) : gasUsdNum.toFixed(2);
45
60
  if (isJsonMode()) {
46
61
  out({ gasEth, gasUsd, gasLimit: gasLimit.toString(), gasPrice: gasPrice.toString() });
47
62
  }
@@ -122,6 +122,9 @@ export function gasCmd() {
122
122
  }
123
123
  catch (e) {
124
124
  const msg = e instanceof Error ? e.message : String(e);
125
+ if (msg.includes("OVERFLOW") || msg.includes("overflow")) {
126
+ exitWithError(`Amount may be too large for this route (aggregator overflow). Try a smaller amount (e.g. 100 or 300).${usageHint("gas")}`, "GAS_ERROR");
127
+ }
125
128
  exitWithError(`${msg}.${usageHint("gas")}`, "GAS_ERROR");
126
129
  }
127
130
  });
@@ -3,15 +3,25 @@ import ora from "ora";
3
3
  import { getAddress } from "../wallet.js";
4
4
  import { get0xQuote } from "../lib/zerox.js";
5
5
  import { parseTokenAmountToWei } from "../lib/parse-amount.js";
6
- import { resolveChainId, getChainOptionsHint } from "../constants.js";
6
+ import { resolveChainId, getChainOptionsHint, SPEED_TOKEN_ADDRESS, NATIVE_ETH_0X } from "../constants.js";
7
7
  import { getDefaultChainInput } from "./config.js";
8
8
  import { out, exitWithError, setJsonMode, isJsonMode, usageHint } from "../output.js";
9
+ function toToken(v, defaultVal) {
10
+ if (!v)
11
+ return defaultVal;
12
+ const t = v.trim().toLowerCase();
13
+ if (t === "speed")
14
+ return SPEED_TOKEN_ADDRESS;
15
+ if (t === "eth" || t === "ether" || t === "native")
16
+ return NATIVE_ETH_0X;
17
+ return v.trim();
18
+ }
9
19
  export function quoteCmd() {
10
20
  return new Command("quote")
11
21
  .description("Preview swap (no tx). To execute, use: speed swap --buy <addr> -a <amount> (approve is automatic)")
12
22
  .option("-c, --chain <id|name>", "Chain ID or name", "8453")
13
- .option("--sell <address>", "Sell token address (default: Speed)")
14
- .option("--buy <address>", "Buy token address")
23
+ .option("--sell <address>", "Sell token: address or 'speed'|'eth'|'native' (default: native ETH). To buy Speed with ETH use --sell eth.")
24
+ .option("--buy <address>", "Buy token: address or 'speed'")
15
25
  .option("-a, --amount <amount>", "Sell amount in token units (e.g. 0.002, 10000)")
16
26
  .action(async function (opts) {
17
27
  setJsonMode(this.parent?.opts().json ?? false);
@@ -22,8 +32,11 @@ export function quoteCmd() {
22
32
  if (!opts.buy || !opts.amount) {
23
33
  exitWithError("--buy and --amount are required", "MISSING_ARGS");
24
34
  }
25
- const sellToken = opts.sell?.trim() ?? "0xB01CF1bE9568f09449382a47Cd5bF58e2A9D5922";
26
- const buyToken = opts.buy.trim();
35
+ const sellToken = toToken(opts.sell, NATIVE_ETH_0X);
36
+ const buyToken = toToken(opts.buy, SPEED_TOKEN_ADDRESS);
37
+ if (sellToken.toLowerCase() === buyToken.toLowerCase()) {
38
+ exitWithError(`Sell and buy tokens must be different. To buy Speed with ETH use --sell eth (or --sell ${NATIVE_ETH_0X}).${usageHint("quote")}`, "SAME_TOKEN");
39
+ }
27
40
  const amount = parseTokenAmountToWei(opts.amount.trim());
28
41
  try {
29
42
  const spinner = isJsonMode() ? null : ora("Fetching quote...").start();
@@ -45,10 +45,10 @@ export function swapCmd() {
45
45
  return new Command("swap")
46
46
  .description("One-shot swap: get quote → confirm → approve (if needed) → execute. No need to run quote or approve separately.")
47
47
  .option("-c, --chain <id|name>", "Chain ID or name (e.g. 8453, base)", "8453")
48
- .option("--sell <address>", "Sell token (default: Speed)")
49
- .option("--buy <address>", "Buy token (default: Speed)")
48
+ .option("--sell <address>", "Sell token: address, or 'speed'|'eth'|'native' (default: native ETH). To buy Speed with ETH use default or --sell eth.")
49
+ .option("--buy <address>", "Buy token: address or 'speed' (default: Speed)")
50
50
  .option("-a, --amount <amount>", "Sell amount in token units (e.g. 0.002, 10000, or 0.002 eth / 100 speed)")
51
- .option("--go", "Skip confirmation and execute swap")
51
+ .option("--go", "Skip confirmation (alias for -y/--yes for swap)")
52
52
  .option("--dry-run", "Only fetch and print quote; no approval or swap tx")
53
53
  .action(async function (opts) {
54
54
  setJsonMode(this.parent?.opts().json ?? false);
@@ -74,7 +74,7 @@ export function swapCmd() {
74
74
  const sellToken = toToken(opts.sell, NATIVE_ETH_0X);
75
75
  const buyToken = toToken(opts.buy, SPEED_TOKEN_ADDRESS);
76
76
  if (sellToken.toLowerCase() === buyToken.toLowerCase()) {
77
- exitWithError("Sell and buy token must be different. Use --sell and/or --buy to specify.", "SAME_TOKEN");
77
+ exitWithError(`Sell and buy tokens must be different. To buy Speed with ETH use default or --sell eth (or --sell ${NATIVE_ETH_0X}).${usageHint("swap")}`, "SAME_TOKEN");
78
78
  }
79
79
  const amount = parseTokenAmountToWei(opts.amount.trim());
80
80
  try {
@@ -6,7 +6,7 @@ import { executeSwap } from "../lib/swap-execute.js";
6
6
  import { getEthUsdPriceNumber } from "../lib/oracle.js";
7
7
  import { recordXpAction } from "../lib/xp.js";
8
8
  import { parseTokenAmountToWei } from "../lib/parse-amount.js";
9
- import { resolveChainId, getChainOptionsHint, resolveTokenAddress, NATIVE_ETH_0X, EXPLORER_URLS, } from "../constants.js";
9
+ import { resolveChainId, getChainOptionsHint, resolveTokenAddress, NATIVE_ETH_0X, EXPLORER_URLS, CHAIN_NAMES, } from "../constants.js";
10
10
  import { getDefaultChainInput } from "./config.js";
11
11
  import { out, exitWithError, setJsonMode, isJsonMode, success, usageHint } from "../output.js";
12
12
  const ERC20_BALANCE_ABI = ["function balanceOf(address owner) view returns (uint256)"];
@@ -36,6 +36,15 @@ function jitteredDelaySeconds(centerSec, jitterFraction) {
36
36
  function sleepMs(ms) {
37
37
  return new Promise((resolve) => setTimeout(resolve, ms));
38
38
  }
39
+ /** Turn RPC "insufficient funds" into a short, actionable message. */
40
+ function formatInsufficientFundsMessage(chainId, rawMessage) {
41
+ const chainName = CHAIN_NAMES[chainId] ?? String(chainId);
42
+ const haveMatch = rawMessage.match(/have\s+(\d+)/);
43
+ const wantMatch = rawMessage.match(/want\s+(\d+)/);
44
+ const haveEth = haveMatch ? ethers.formatEther(haveMatch[1]) : "?";
45
+ const wantEth = wantMatch ? ethers.formatEther(wantMatch[1]) : "?";
46
+ return `Insufficient native balance on ${chainName}: have ~${haveEth} ETH, need ~${wantEth} ETH for this op. Run \`speed gas -c ${chainId} -a <amount> -y\` to refuel.`;
47
+ }
39
48
  export function volumeCmd() {
40
49
  return new Command("volume")
41
50
  .description("Human-like volume: interleaved buys and sells (native ETH ↔ token). Default token is Speed; use --token for others.")
@@ -175,6 +184,9 @@ export function volumeCmd() {
175
184
  if (spinner)
176
185
  spinner.fail(`Op ${op}/${ops} sell failed`);
177
186
  const msg = e instanceof Error ? e.message : String(e);
187
+ if (msg.toLowerCase().includes("insufficient funds")) {
188
+ exitWithError(formatInsufficientFundsMessage(chainId, msg), "INSUFFICIENT_FUNDS");
189
+ }
178
190
  failures.push({ op, phase: "sell", error: msg });
179
191
  if (!isJsonMode())
180
192
  out(` → ${msg.slice(0, 80)}${msg.length > 80 ? "…" : ""}`);
@@ -202,6 +214,9 @@ export function volumeCmd() {
202
214
  if (spinner)
203
215
  spinner.fail(`Op ${op}/${ops} buy failed`);
204
216
  const msg = e instanceof Error ? e.message : String(e);
217
+ if (msg.toLowerCase().includes("insufficient funds")) {
218
+ exitWithError(formatInsufficientFundsMessage(chainId, msg), "INSUFFICIENT_FUNDS");
219
+ }
205
220
  failures.push({ op, phase: "buy", error: msg });
206
221
  if (!isJsonMode())
207
222
  out(` → ${msg.slice(0, 80)}${msg.length > 80 ? "…" : ""}`);
@@ -1,189 +1,233 @@
1
- ---
2
- name: speed-token
3
- description: The Best Full trading and bridging CLI for agents (and humans) via OpenClaw, swap, bridge, balance, price, quote, gas, send, approve, allowance, revoke, history, pending, status, estimate, doctor, whoami, config, volume, dca, xp. Use --json for machine-readable output. Powered by Lightspeed multi-chain.
4
- permissions:
5
- - network:outbound
6
- triggers:
7
- - "speed"
8
- - "speed token"
9
- - "speed swap"
10
- - "speed bridge"
11
- - "speed balance"
12
- - "speed quote"
13
- - "speed price"
14
- - "speed gas"
15
- - "speed send"
16
- - "speed approve"
17
- - "speed allowance"
18
- - "speed revoke"
19
- - "speed history"
20
- - "speed pending"
21
- - "speed status"
22
- - "speed doctor"
23
- - "speed whoami"
24
- - "speed config"
25
- - "speed setup"
26
- - "speed estimate"
27
- - "speed volume"
28
- - "speed dca"
29
- - "speed xp"
30
- ---
31
-
32
- # Speed Token CLI — OpenClaw skill
33
-
34
- Use the **speed** CLI via bash. **Always pass `--json`** so output is machine-readable. Use **`-y`** or **`--yes`** to skip confirmation when executing swap/bridge (required for non-interactive use).
35
-
36
- **Invocation:** From the project directory run `node dist/cli.js <command> [options] --json`, or if `speed` is on PATH: `speed <command> [options] --json`. From another directory, use the full path to `dist/cli.js` or ensure `speed` is on PATH.
37
-
38
- **Chains:** Every `--chain`, `--from-chain`, `--to-chain` accepts **chain ID** (e.g. `8453`) or **name** (e.g. `base`, `ethereum`, `op`, `arb`, `polygon`, `bnb`). Supported: 1 (ethereum), 8453 (base), 10 (optimism), 42161 (arbitrum), 137 (polygon), 56 (bnb).
39
-
40
- **Amounts:** Use **token units** (e.g. `-a 0.002`, `-a 1000`), not wei. Commands that take `-a` accept human-readable amounts.
41
-
42
- **Speed token (default):** Address `0xB01CF1bE9568f09449382a47Cd5bF58e2A9D5922`. Volume, DCA, and gas default to Speed; use `--token <address|speed>` to use another token.
43
-
44
- **Errors in --json mode:** CLI prints `{"error":"...", "code":"..."}` to stdout and exits 1. Parse and surface the `error` string to the user.
45
-
46
- ---
47
-
48
- ## Global options (before command)
49
-
50
- - `--json` — **Always use.** JSON to stdout; errors as `{ error, code }`.
51
- - `-y, --yes` — Skip confirmation (required for swap, bridge, and gas in non-interactive use).
52
-
53
- ---
54
-
55
- ## Commands reference
56
-
57
- ### Identity & setup
58
-
59
- - **whoami** Print wallet address (from PRIVATE_KEY). No args.
60
- `speed whoami --json`
61
- If this fails, user must run `speed setup` (interactive; do not run from bot).
62
-
63
- - **setup** — Interactive; writes secrets to `~/.speed/.env`. **Do not invoke from bots.** Direct user to run `speed setup` if whoami or doctor fails.
64
-
65
- - **doctor** — Validate env, API keys, RPC, oracles, Speed balance.
66
- `speed doctor --json` or `speed doctor -c base --json`
67
-
68
- ### Balance & price
69
-
70
- - **balance** Speed + native + optional extra tokens. Omit `-c` for all chains.
71
- `speed balance --json`
72
- `speed balance -c base --json`
73
- `speed balance -c base -t <token-address> --json` (repeat `-t` for multiple)
74
-
75
- - **price** Speed/ETH, Speed/USD, native USD (oracle).
76
- `speed price -c base --json`
77
-
78
- ### Swap (one-shot: quote approve if needed swap)
79
-
80
- - **swap** Single command to execute a swap. Approve is automatic when needed. Use `-y` to skip confirmation.
81
- `speed swap -c base --buy <token-address> -a 0.002 -y --json`
82
- Optional: `--sell <address>` (default Speed).
83
- **Preview only (no tx):** `speed swap --dry-run -c base --buy <addr> -a 0.002 --json`
84
-
85
- - **quote** — Preview swap (no transaction).
86
- `speed quote -c base --buy <token-address> -a 0.002 --json`
87
- Optional: `--sell <address>`.
88
-
89
- **Do not** tell users to run approve then quote then swap; **swap alone** does it. Use **quote** or **swap --dry-run** only when the user wants a preview.
90
-
91
- ### Bridge
92
-
93
- - **bridge** — Bridge Speed across chains (Squid). Use `-y` to skip confirmation.
94
- `speed bridge --from-chain base --to-chain ethereum -a 100 -y --json`
95
- Optional: `--to-token <address>` (default Speed on destination).
96
-
97
- ### Volume & DCA (automated buy/sell)
98
-
99
- - **volume** — Human-like volume: interleaved buys and sells (ETH ↔ token) with random-walk amounts, jittered delays, optional partial sells. Default token is Speed; use `--token <address|speed>` for another token. Continues on revert; failures are reported in summary.
100
- `speed volume -c base -a 0.001 --ops 20 --delay 2 --delay-jitter 0.5 --sell-frequency 0.2 --json`
101
- Optional: `--token`, `--amount-min`, `--amount-max`, `--amount-drift`, `--sell-partial-chance`, `--dry-run`.
102
-
103
- - **dca** — DCA: buy token with ETH on a fixed time interval. Default token is Speed; use `--token <address|speed>` for another token. Runs until `--count` buys or until stopped (Ctrl+C).
104
- `speed dca -c base -a 0.001 --interval 5m --count 10 --json`
105
- Optional: `--token`, `--interval-jitter <fraction>`, `--dry-run`. Omit `--count` to run until stopped.
106
-
107
- ### Gas (token → native)
108
-
109
- - **gas** — Swap token for native (ETH/MATIC/BNB) to fund gas. Default token is Speed; use `--token <address|speed>` for another token. Use `-y` for non-interactive.
110
- `speed gas -c base -a 10000 -y --json`
111
-
112
- ### Send & allowances
113
-
114
- - **send** — Plain ERC-20 transfer of Speed.
115
- `speed send -c base -t <recipient-address> -a 100 -y --json`
116
-
117
- - **approve** Set token allowance for a spender (e.g. for scripting). Amount in token units or `max`.
118
- `speed approve -c base --token <token-address> --spender <spender-address> -a 1000 --json` or `-a max --json`
119
-
120
- - **allowance** Read current allowance.
121
- `speed allowance -c base --token <token-address> --spender <spender-address> --json`
122
-
123
- - **revoke** — Set allowance to 0.
124
- `speed revoke -c base --token <token-address> --spender <spender-address> -y --json`
125
-
126
- ### History & status
127
-
128
- - **history** Recent transfers (Alchemy). Omit `-c` for all chains.
129
- `speed history --json` or `speed history -c base -n 20 --json`
130
-
131
- - **pending** — In-flight bridges + pending txs.
132
- `speed pending --json` or `speed pending --no-txs --json` (bridges only)
133
-
134
- - **status** — Tx confirmation; for bridge use Squid status.
135
- On-chain: `speed status --tx <tx-hash> -c base --json`
136
- Bridge: `speed status --tx <tx-hash> --request-id <id> --quote-id <id> --json`
137
-
138
- ### XP (progress for bots)
139
-
140
- - **xp** — Show level, streak, and stats (swaps, bridges, volume ops, DCA buys, gas refuels). Bots call this to see how they're doing. Stored in `~/.speed/xp.json`.
141
- `speed xp --json`
142
- Optional: `--no-title` to omit the silly level title.
143
-
144
- ### Estimate & config
145
-
146
- - **estimate** Gas cost (ETH + USD) for swap or bridge. Amount in token units (same as swap).
147
- Swap: `speed estimate -c base --buy <addr> -a 0.002 --json`
148
- Bridge: `speed estimate -c base --to-chain ethereum --bridge --json`
149
-
150
- - **config** — Read/write `~/.speed/config.json` (no secrets).
151
- Set: `speed config set default-chain 8453 --json`
152
- Get: `speed config get --json` or `speed config get default-chain --json`
153
- Keys: `default-chain`, `default-slippage`, `output-format` (human|json).
154
-
155
- ---
156
-
157
- ## Recommended flows for bots
158
-
159
- 1. **User wants to swap**
160
- Run: `speed swap -c <chain> --buy <token> -a <amount> -y --json`. If user wants a preview first, run `speed swap --dry-run ... --json` then same without `--dry-run` and without `-y` only if you need to ask for confirmation.
161
-
162
- 2. **User wants to bridge**
163
- Run: `speed bridge --from-chain <id|name> --to-chain <id|name> -a <amount> -y --json`.
164
-
165
- 3. **User wants balance**
166
- Run: `speed balance --json` (all chains) or `speed balance -c <chain> --json`.
167
-
168
- 4. **User wants price**
169
- Run: `speed price -c <chain> --json`.
170
-
171
- 5. **User wants to fund gas (token → native)**
172
- Run: `speed gas -c <chain> -a <token-amount> -y --json`. Default token is Speed; add `--token <address|speed>` for another token.
173
-
174
- 6. **User wants volume (automated buys + sells)**
175
- Run: `speed volume -c <chain> -a <eth-per-buy> --ops <n> --delay <sec> --sell-frequency <0..1> --json`. Default token is Speed; add `--token <address|speed>` for another token. Failures do not stop the run; summary includes failed count.
176
-
177
- 7. **User wants DCA (interval buys only)**
178
- Run: `speed dca -c <chain> -a <eth-per-buy> --interval <sec|5m|1h|1d> --count <n> --json`, or omit `--count` to run until stopped. Default token is Speed; add `--token <address|speed>` for another token.
179
-
180
- 8. **User wants to see XP / progress**
181
- Run: `speed xp --json`. Returns totalXP, level, title, streak, lastActivity, progress to next level, stats (count + totalUSD per action type), recent history.
182
-
183
- 9. **User wants gas estimate before swap/bridge**
184
- Run: `speed estimate -c <chain> --buy <addr> -a <token-amount> --json` (swap) or `speed estimate -c <chain> --to-chain <id|name> --bridge --json` (bridge). Use same `-a` as the swap for comparable cost.
185
-
186
- 10. **Check if CLI is configured**
187
- Run: `speed doctor --json` or `speed whoami --json`. If error, tell user to run `speed setup` in the terminal (interactive).
188
-
189
- 11. **Parse JSON:** On success, one JSON object per command. On failure, `{ error, code }`; show `error` to the user. Common success shapes: whoami `{ address }`, balance `{ address?, chains }`, swap/bridge/gas/send/approve `{ txHash, explorerLink? }`, quote `{ buyAmountWei?, ... }`, price `{ speedPerEth?, ... }`, xp `{ totalXP, level, streak, ... }`, estimate `{ gasCostEth?, gasCostUsd?, ... }`.
1
+ ---
2
+ name: speed-token
3
+ description: The Best Full trading and bridging CLI for agents (and humans) via OpenClaw, swap, bridge, balance, price, quote, gas, send, approve, allowance, revoke, history, pending, status, estimate, doctor, whoami, config, volume, dca, xp. Use --json for machine-readable output. Powered by Lightspeed multi-chain.
4
+ permissions:
5
+ - network:outbound
6
+ triggers:
7
+ - "speed"
8
+ - "speed token"
9
+ - "speed swap"
10
+ - "speed bridge"
11
+ - "speed balance"
12
+ - "speed quote"
13
+ - "speed price"
14
+ - "speed gas"
15
+ - "speed send"
16
+ - "speed approve"
17
+ - "speed allowance"
18
+ - "speed revoke"
19
+ - "speed history"
20
+ - "speed pending"
21
+ - "speed status"
22
+ - "speed doctor"
23
+ - "speed whoami"
24
+ - "speed config"
25
+ - "speed setup"
26
+ - "speed estimate"
27
+ - "speed volume"
28
+ - "speed dca"
29
+ - "speed xp"
30
+ ---
31
+
32
+ # Speed Token CLI — OpenClaw skill
33
+
34
+ Use the **speed** CLI via bash. **Always pass `--json`** so output is machine-readable. Use **`-y`** or **`--yes`** to skip confirmation when executing swap, bridge, or gas (required for non-interactive use). For swap you can also use **`--go`** as an alias.
35
+
36
+ **Invocation:** From the project directory run `node dist/cli.js <command> [options] --json` (or put global options first: `node dist/cli.js --json -y <command> [options]`). If `speed` is on PATH: `speed <command> [options] --json`. From another directory, use the full path to `dist/cli.js` or ensure `speed` is on PATH.
37
+
38
+ **Chains:** Every `--chain`, `--from-chain`, `--to-chain` accepts **chain ID** (e.g. `8453`) or **name** (e.g. `base`, `ethereum`, `op`, `arb`, `polygon`, `bnb`). Supported: 1 (ethereum), 8453 (base), 10 (optimism), 42161 (arbitrum), 137 (polygon), 56 (bnb).
39
+
40
+ **Amounts:** Use **token units** (e.g. `-a 0.002`, `-a 1000`), not wei. Commands that take `-a` accept human-readable amounts.
41
+
42
+ **Speed token (default):** Address `0xB01CF1bE9568f09449382a47Cd5bF58e2A9D5922`. Volume, DCA, and gas default to Speed; use `--token <address|speed>` to use another token.
43
+
44
+ **Errors in --json mode:** CLI prints `{"error":"...", "code":"..."}` to stdout and exits 1. Parse and surface the `error` string to the user. Common codes: `INSUFFICIENT_FUNDS`, `SAME_TOKEN`, `QUOTE_ERROR`, `MISSING_ARGS`, `INVALID_CHAIN`.
45
+
46
+ **Shell note:** Examples use `||` (Bash). On PowerShell use `;` instead of `||` to chain commands.
47
+
48
+ **Pitfalls:** (1) Volume/DCA need enough native balance (~0.001+ ETH per buy); otherwise INSUFFICIENT_FUNDS. (2) Very small DCA/swap amounts can revert (slippage/minimum); use ~0.001 ETH or more. (3) To sell "all" Speed, read balance first and pass that amount to swap (round down slightly).
49
+
50
+ ---
51
+
52
+ ## Trade like a pro (agent best practices)
53
+
54
+ - **Before any trade:** Run `speed balance -c <chain> --json` and optionally `speed price -c <chain> --json` so you know native balance, token balance, and prices. Ensure sell token balance ≥ amount (or for buy-with-ETH, native balance ≥ amount + gas).
55
+ - **Preview first when it matters:** Use `speed quote -c <chain> --sell <x> --buy <y> -a <amount> --json` or `speed swap --dry-run ... --json` before large or one-off swaps. Use `speed estimate -c <chain> --sell eth --buy speed -a <amount> --json` to see gas cost.
56
+ - **Buy Speed with ETH:** Default is already sell ETH / buy Speed. Use `speed swap -c <chain> -a <eth-amount> -y --json` (no need to pass --sell/--buy). Or explicitly `--sell eth` or `--sell native`.
57
+ - **Sell Speed for ETH (or “sell all”):** (1) `speed balance -c <chain> --json` → parse Speed token `balance` for that chain. (2) Round down slightly (e.g. 2 decimals). (3) `speed swap -c <chain> --sell speed --buy eth -a <amount> -y --json`.
58
+ - **Volume:** Use `-a 0.0008` or `0.001` per buy for reliability. Ensure native balance covers (ops × amount + gas). Use `--ops` to control how many buy/sell cycles. Failures are reported in summary; run continues.
59
+ - **DCA:** Use at least `-a 0.001` per buy. Use `--count` so the run ends (e.g. `--count 5`). Space intervals (e.g. `--interval 30s`) to avoid nonce/rate issues.
60
+ - **Bridges:** Squid can rate-limit (429). Space bridge calls (e.g. one chain at a time, wait between). On 429, message suggests waiting and retrying.
61
+ - **Gas (token → native):** If you see OVERFLOW, use a smaller amount (e.g. `-a 100` or `-a 300`). Large token amounts can overflow the aggregator path.
62
+ - **Never sell and buy the same token:** CLI validates and returns SAME_TOKEN; use `--sell eth` when you want to buy Speed with ETH.
63
+
64
+ ---
65
+
66
+ ## XP and leveling (level up)
67
+
68
+ Actions that grant **XP** (stored in `~/.speed/xp.json`):
69
+
70
+ | Action | Base XP | When it’s recorded |
71
+ |------------|--------|---------------------|
72
+ | **swap** | 10 | Each swap (buy or sell) |
73
+ | **bridge** | 25 | Each bridge tx |
74
+ | **volumeOp** | 3 | Each volume buy or sell op |
75
+ | **dcaBuy** | 8 | Each DCA buy |
76
+ | **gasRefuel** | 3 | Each gas (token→native) tx |
77
+
78
+ XP per action is scaled by **USD value** of the trade (log scale; higher USD = more XP) and by **daily streak** (up to 1.5× for consecutive days of activity). Small USD actions still grant at least a small amount of XP.
79
+
80
+ - **Check progress:** `speed xp --json` `totalXP`, `level`, `title`, `streak`, `progress` (e.g. `current`, `needed`, `fraction`), `stats` (count and totalUSD per action), `recentHistory`.
81
+ - **Level thresholds:** Level 1 2 at **500** total XP; level 2 → 3 at **500 + 1319** total XP; each next level needs more (formula: 500 × level^1.4).
82
+ - **To level up:** Prefer a mix of (1) **volume** (many `volumeOp`s per run: `speed volume -c base -a 0.001 --ops 20 -y --json`), (2) **swaps** (each gives XP; larger USD = more XP), (3) **bridges** (high base XP), (4) **DCA** (`dcaBuy` per buy). Keep the streak by doing at least one action per day.
83
+ - **Efficient XP grind:** Run volume with moderate `--ops` (e.g. 15–25) and `-a 0.0008`–`0.001`; then do a few swaps (buy and sell). Use `speed xp --json` to see how close you are to the next level.
84
+
85
+ ---
86
+
87
+ ## Global options (before command)
88
+
89
+ - `--json` — **Always use.** JSON to stdout; errors as `{ error, code }`.
90
+ - `-y, --yes` — Skip confirmation (required for swap, bridge, and gas in non-interactive use).
91
+
92
+ ---
93
+
94
+ ## Commands reference
95
+
96
+ ### Identity & setup
97
+
98
+ - **whoami** — Print wallet address (from PRIVATE_KEY). No args.
99
+ `speed whoami --json`
100
+ If this fails, user must run `speed setup` (interactive; do not run from bot).
101
+
102
+ - **setup** — Interactive; writes secrets to `~/.speed/.env`. **Do not invoke from bots.** Direct user to run `speed setup` if whoami or doctor fails.
103
+
104
+ - **doctor** Validate env, API keys, RPC, oracles, Speed balance.
105
+ `speed doctor --json` or `speed doctor -c base --json`
106
+
107
+ ### Balance & price
108
+
109
+ - **balance** — Speed + native + optional extra tokens. Omit `-c` for all chains; use `-c base` or `-c 8453` for one chain. JSON: `chains[].chainId`, `chains[].nativeBalance` (string), `chains[].tokens[].symbol`, `tokens[].balance` (string, in token units). Use the Speed token `balance` for a chain when you need to sell that amount.
110
+ `speed balance --json`
111
+ `speed balance -c base --json`
112
+ `speed balance -c base -t <token-address> --json` (repeat `-t` for multiple)
113
+
114
+ - **price** — Speed/ETH, Speed/USD, native USD (oracle).
115
+ `speed price -c base --json`
116
+
117
+ ### Swap (one-shot: quote approve if needed swap)
118
+
119
+ - **swap** — Single command to execute a swap. Approve is automatic when needed. Use `-y` or `--go` to skip confirmation.
120
+ `speed swap -c base --buy <token-address> -a 0.002 -y --json`
121
+ To **buy Speed with native ETH**: default is sell ETH / buy Speed; or set `--sell eth` or `--sell native`. Optional: `--sell <address|speed|eth|native>`, `--buy <address|speed>`.
122
+ **Preview only (no tx):** `speed swap --dry-run -c base --buy <addr> -a 0.002 --json`
123
+
124
+ - **quote** Preview swap (no transaction). Default sell is native ETH. Use `--sell eth` or `--sell native` like swap.
125
+ `speed quote -c base --sell eth --buy speed -a 0.002 --json`
126
+ Optional: `--sell <address|speed|eth|native>`, `--buy <address|speed>`.
127
+
128
+ **Sell Speed for ETH:** `speed swap -c <chain> --sell speed --buy eth -a <amount> -y --json`. Get `<amount>` from `speed balance -c <chain> --json` (parse Speed token `balance` for that chain). Round down slightly (e.g. 2 decimals) to avoid dust/slippage.
129
+
130
+ **Do not** tell users to run approve then quote then swap; **swap alone** does it. Use **quote** or **swap --dry-run** only when the user wants a preview.
131
+
132
+ ### Bridge
133
+
134
+ - **bridge** — Bridge Speed across chains (Squid). Use `-y` to skip confirmation.
135
+ `speed bridge --from-chain base --to-chain ethereum -a 100 -y --json`
136
+ Optional: `--to-token <address>` (default Speed on destination).
137
+
138
+ ### Volume & DCA (automated buy/sell)
139
+
140
+ - **volume** — Human-like volume: interleaved buys and sells (ETH token) with random-walk amounts, jittered delays, optional partial sells. Default token is Speed; use `--token <address|speed>` for another token. **Requires enough native balance:** need at least ~0.001 ETH per buy + gas; otherwise first op can exit with `INSUFFICIENT_FUNDS`. Some ops may revert (slippage); run continues; summary has `buys`, `sells`, `failed`, `totalOps`. Use `-a 0.0008` or higher for reliability.
141
+ `speed volume -c base -a 0.001 --ops 20 --delay 2 --delay-jitter 0.5 --sell-frequency 0.2 -y --json`
142
+ Optional: `--token`, `--amount-min`, `--amount-max`, `--amount-drift`, `--sell-partial-chance`, `--dry-run`.
143
+
144
+ - **dca** DCA: buy token with ETH on a fixed time interval. Default token is Speed; use `--token <address|speed>` for another token. **Minimum amount:** very small amounts (e.g. 0.0004–0.0005 ETH) often revert with "slippage, liquidity, or minimum amount"; use at least ~0.001 ETH per buy. `--interval` accepts seconds or `20s`, `5m`, `1h`, `1d`. Runs until `--count` buys or until stopped (Ctrl+C).
145
+ `speed dca -c base -a 0.001 --interval 5m --count 10 -y --json`
146
+ Optional: `--token`, `--interval-jitter <fraction>`, `--dry-run`. Omit `--count` to run until stopped.
147
+
148
+ ### Gas (token native)
149
+
150
+ - **gas** — Swap token for native (ETH/MATIC/BNB) to fund gas. Default token is Speed; use `--token <address|speed>` for another token. Use `-y` for non-interactive.
151
+ `speed gas -c base -a 10000 -y --json`
152
+
153
+ ### Send & allowances
154
+
155
+ - **send** — Plain ERC-20 transfer of Speed.
156
+ `speed send -c base -t <recipient-address> -a 100 -y --json`
157
+
158
+ - **approve** — Set token allowance for a spender (e.g. for scripting). Amount in token units or `max`.
159
+ `speed approve -c base --token <token-address> --spender <spender-address> -a 1000 --json` or `-a max --json`
160
+
161
+ - **allowance** — Read current allowance.
162
+ `speed allowance -c base --token <token-address> --spender <spender-address> --json`
163
+
164
+ - **revoke** — Set allowance to 0.
165
+ `speed revoke -c base --token <token-address> --spender <spender-address> -y --json`
166
+
167
+ ### History & status
168
+
169
+ - **history** Recent transfers (Alchemy). Omit `-c` for all chains.
170
+ `speed history --json` or `speed history -c base -n 20 --json`
171
+
172
+ - **pending** In-flight bridges + pending txs.
173
+ `speed pending --json` or `speed pending --no-txs --json` (bridges only)
174
+
175
+ - **status** Tx confirmation; for bridge use Squid status.
176
+ On-chain: `speed status --tx <tx-hash> -c base --json`
177
+ Bridge: `speed status --tx <tx-hash> --request-id <id> --quote-id <id> --json`
178
+
179
+ ### XP (progress for bots)
180
+
181
+ - **xp** Show level, streak, and stats (swaps, bridges, volume ops, DCA buys, gas refuels). Bots call this to see how they're doing. Stored in `~/.speed/xp.json`.
182
+ `speed xp --json`
183
+ Optional: `--no-title` to omit the silly level title.
184
+
185
+ ### Estimate & config
186
+
187
+ - **estimate** Gas cost (ETH + USD) for swap or bridge. Amount in token units (same as swap). Same `--sell`/`--buy` tokens as swap (e.g. `--sell eth --buy speed`).
188
+ Swap: `speed estimate -c base --sell eth --buy speed -a 0.002 --json`
189
+ Bridge: `speed estimate -c base --to-chain ethereum --bridge --json`
190
+
191
+ - **config** — Read/write `~/.speed/config.json` (no secrets).
192
+ Set: `speed config set default-chain 8453 --json`
193
+ Get: `speed config get --json` or `speed config get default-chain --json`
194
+ Keys: `default-chain`, `default-slippage`, `output-format` (human|json).
195
+
196
+ ---
197
+
198
+ ## Recommended flows for bots
199
+
200
+ 1. **User wants to swap**
201
+ Run: `speed swap -c <chain> --buy <token> -a <amount> -y --json`. If user wants a preview first, run `speed swap --dry-run ... --json` then same without `--dry-run` and without `-y` only if you need to ask for confirmation.
202
+
203
+ 2. **User wants to bridge**
204
+ Run: `speed bridge --from-chain <id|name> --to-chain <id|name> -a <amount> -y --json`.
205
+
206
+ 3. **User wants balance**
207
+ Run: `speed balance --json` (all chains) or `speed balance -c <chain> --json`.
208
+
209
+ 4. **User wants price**
210
+ Run: `speed price -c <chain> --json`.
211
+
212
+ 5. **User wants to fund gas (token → native)**
213
+ Run: `speed gas -c <chain> -a <token-amount> -y --json`. Default token is Speed; add `--token <address|speed>` for another token.
214
+
215
+ 6. **User wants volume (automated buys + sells)**
216
+ Run: `speed volume -c <chain> -a <eth-per-buy> --ops <n> -y --json`. Use at least ~0.0008 ETH per buy. Failures do not stop the run; summary has `buys`, `sells`, `failed`, `totalOps`. Optional: `--delay`, `--sell-frequency`, `--token`.
217
+
218
+ 7. **User wants DCA (interval buys only)**
219
+ Run: `speed dca -c <chain> -a <eth-per-buy> --interval <20s|5m|1h|1d> --count <n> -y --json`. Use at least ~0.001 ETH per buy to avoid slippage reverts. Omit `--count` to run until stopped. Default token is Speed; add `--token <address|speed>` for another token.
220
+
221
+ 8. **User wants to see XP / progress**
222
+ Run: `speed xp --json`. Returns totalXP, level, title, streak, lastActivity, progress to next level, stats (count + totalUSD per action type), recent history.
223
+
224
+ 9. **User wants gas estimate before swap/bridge**
225
+ Run: `speed estimate -c <chain> --buy <addr> -a <token-amount> --json` (swap) or `speed estimate -c <chain> --to-chain <id|name> --bridge --json` (bridge). Use same `-a` as the swap for comparable cost.
226
+
227
+ 10. **Check if CLI is configured**
228
+ Run: `speed doctor --json` or `speed whoami --json`. If error, tell user to run `speed setup` in the terminal (interactive).
229
+
230
+ 11. **User wants to sell Speed for ETH (or “sell all”)**
231
+ Run: `speed balance -c <chain> --json`, parse the chain’s Speed token `balance` (string, token units). Then run: `speed swap -c <chain> --sell speed --buy eth -a <amount> -y --json` with that amount (round down slightly to avoid dust).
232
+
233
+ 12. **Parse JSON:** On success, one JSON object per command. On failure, `{ error, code }`; show `error` to the user. Common success shapes: whoami `{ address }`, balance `{ address?, chains: [{ chainId, nativeBalance, tokens: [{ symbol, balance }] }] }`, swap/bridge/gas/send/approve `{ txHash, explorerLink? }`, quote `{ sellAmount, buyAmount, ... }`, price `{ speedPerNative, nativeUsd, ... }`, xp `{ totalXP, level, streak, stats: { swaps, volumeOps, dcaBuys, ... }, recentHistory }`, estimate `{ gasEth, gasUsd, ... }`, volume `{ summary: { buys, sells, failed, totalOps }, results, failures? }`.
package/package.json CHANGED
@@ -1,47 +1,50 @@
1
- {
2
- "name": "@lightspeed-cli/speed-cli",
3
- "version": "0.1.2",
4
- "description": "Speed Token CLI: swap, bridge, balance, price, volume, DCA, gas, XP. Uses 0x and Squid; config in ~/.speed.",
5
- "type": "module",
6
- "bin": {
7
- "speed": "dist/cli.js"
8
- },
9
- "files": [
10
- "dist",
11
- "openclaw"
12
- ],
13
- "scripts": {
14
- "build": "tsc",
15
- "start": "node dist/cli.js",
16
- "dev": "tsc --watch",
17
- "prepublishOnly": "npm run build"
18
- },
19
- "engines": {
20
- "node": ">=18"
21
- },
22
- "keywords": [
23
- "speed",
24
- "token",
25
- "cli",
26
- "swap",
27
- "bridge",
28
- "0x",
29
- "squid",
30
- "ethereum",
31
- "base"
32
- ],
33
- "license": "MIT",
34
- "dependencies": {
35
- "@0xsquid/sdk": "^2.2.0",
36
- "@0xsquid/squid-types": "^0.1.215",
37
- "chalk": "^5.3.0",
38
- "commander": "^12.0.0",
39
- "dotenv": "^16.4.5",
40
- "ethers": "^6.13.0",
41
- "ora": "^8.0.1"
42
- },
43
- "devDependencies": {
44
- "@types/node": "^20.11.0",
45
- "typescript": "^5.3.0"
46
- }
47
- }
1
+ {
2
+ "name": "@lightspeed-cli/speed-cli",
3
+ "version": "0.1.4",
4
+ "description": "Speed Token CLI: swap, bridge, balance, price, volume, DCA, gas, XP. Uses 0x and Squid; config in ~/.speed.",
5
+ "type": "module",
6
+ "bin": {
7
+ "speed": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "openclaw",
12
+ ".env.example"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "start": "node dist/cli.js",
17
+ "dev": "tsc --watch",
18
+ "test": "npm run build && node --test tests/constants.test.js tests/parse-amount.test.js tests/xp.test.js tests/oracle.test.js tests/cli-options.test.js",
19
+ "test:json": "npm run build && node tests/run-json.js",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "keywords": [
26
+ "speed",
27
+ "token",
28
+ "cli",
29
+ "swap",
30
+ "bridge",
31
+ "0x",
32
+ "squid",
33
+ "ethereum",
34
+ "base"
35
+ ],
36
+ "license": "MIT",
37
+ "dependencies": {
38
+ "@0xsquid/sdk": "^2.2.0",
39
+ "@0xsquid/squid-types": "^0.1.215",
40
+ "chalk": "^5.3.0",
41
+ "commander": "^12.0.0",
42
+ "dotenv": "^16.4.5",
43
+ "ethers": "^6.13.0",
44
+ "ora": "^8.0.1"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.11.0",
48
+ "typescript": "^5.3.0"
49
+ }
50
+ }