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
83 changes: 35 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ A CLI for AI-driven and human-operated DeFi workflows on the TRON network throug
- [Quick Start](#quick-start)
- [Install](#install)
- [Example Commands](#example-commands)
- [Wallet Configuration](#wallet-configuration)
- [Runtime Configuration](#runtime-configuration)
- [Configuration](#configuration)
- [Environment Variables](#environment-variables)
- [Wallet Configuration](#wallet-configuration)
- [Network Configuration](#network-configuration)
- [Command Guide](#command-guide)
- [Wallet & Portfolio](#wallet--portfolio)
- [Price & Discovery](#price--discovery)
Expand Down Expand Up @@ -113,7 +115,7 @@ Found 3 route(s) for swap:
(2 more route(s) available, use --all to see them)
```

Wallet-aware:
Wallet-aware: See [Wallet Configuration](#wallet-configuration).

```bash
$ sun wallet address
Expand Down Expand Up @@ -152,50 +154,36 @@ Swap executed successfully

Write operations such as `swap`, `liquidity`, and `contract send` require wallet credentials.

### Wallet Configuration
### Configuration

**Option 1 (Recommended): [Agent Wallet](https://github.com/BofAI/agent-wallet#cli)** — password-protected encrypted keystore, purpose-built for AI agents. Private keys are never stored in plaintext.
#### Environment Variables

```bash
export AGENT_WALLET_PASSWORD=your_wallet_password
export AGENT_WALLET_DIR=/absolute/path/to/.agent # optional, defaults to ~/.agent
```
**CRITICAL SECURITY NOTE**: Never store private keys or mnemonics directly in MCP configuration JSON files such as `claude_desktop_config.json` or `mcp.json`. For wallet setup, use `agent-wallet`'s file-backed configuration and the SDK-supported `AGENT_WALLET_*` settings.

**Option 2: Private key**
The CLI loads environment variables from a local `.env` file via `dotenv`. Use this for non-secret operational settings such as `TRONGRID_API_KEY`, `TRON_NETWORK`, and `TRON_RPC_URL`.

```bash
export AGENT_WALLET_PRIVATE_KEY=your_private_key
# or
export TRON_PRIVATE_KEY=your_private_key
```

**Option 3: Mnemonic**
#### Wallet Configuration

```bash
export AGENT_WALLET_MNEMONIC="word1 word2 word3 ..."
# or
export TRON_MNEMONIC="word1 word2 word3 ..."

export AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX=0 # optional, default 0
# or
export TRON_MNEMONIC_ACCOUNT_INDEX=0 # optional, default 0
```
Wallets are managed through [`agent-wallet`](https://github.com/BofAI/agent-wallet?tab=readme-ov-file#quick-start) file-backed configuration. Install and configure `agent-wallet` first. This repository no longer reads or maps legacy `TRON_PRIVATE_KEY`, `TRON_MNEMONIC`, or `TRON_MNEMONIC_ACCOUNT_INDEX` wallet variables.

> **Note**
> You can also override these per invocation with root-level flags such as `-k`, `-m`, `-i`, `-p`, and `-d`.
> You can override wallet settings for a single invocation with root-level flags such as `-k`, `-m`, `-i`, `-p`, and `-d`. See [`agent-wallet`](https://github.com/BofAI/agent-wallet?tab=readme-ov-file#quick-start) for wallet file formats, local setup, and the full set of SDK-supported `AGENT_WALLET_*` options.

#### Network Configuration

### Runtime Configuration
- `TRON_NETWORK` — optional network override, defaults to `mainnet`
- `TRONGRID_API_KEY` — optional TronGrid API key for higher-rate mainnet access
- `TRON_RPC_URL` — optional custom TRON RPC endpoint

Optional environment variables:
Example:

```bash
export TRON_NETWORK=mainnet
export TRONGRID_API_KEY=your_api_key
export TRONGRID_API_KEY="<YOUR_TRONGRID_API_KEY_HERE>"
export TRON_RPC_URL=https://your-tron-rpc.example
```

The CLI auto-loads `.env` files via `dotenv`, so you can keep these values in a local `.env` file as well.

## Command Guide

### Wallet & Portfolio
Expand Down Expand Up @@ -333,19 +321,19 @@ sun contract send <contractAddress> transfer --args '["TRecipient","1000000"]' -

All commands inherit these root-level flags:

| Flag | Description |
| ---------------------------------------- | ---------------------------------------------------------- |
| `--output <format>` | Output format: `table`, `json`, `tsv` |
| `--json` | Shortcut for JSON output |
| `--fields <list>` | Comma-separated output field filter |
| `--network <network>` | Override `TRON_NETWORK` |
| `-k, --private-key <key>` | Override `TRON_PRIVATE_KEY` for this invocation |
| `-m, --mnemonic <phrase>` | Override `TRON_MNEMONIC` for this invocation |
| `-i, --mnemonic-account-index <index>` | Override `TRON_MNEMONIC_ACCOUNT_INDEX` for this invocation |
| `-p, --agent-wallet-password <password>` | Override `AGENT_WALLET_PASSWORD` for this invocation |
| `-d, --agent-wallet-dir <dir>` | Override `AGENT_WALLET_DIR` for this invocation |
| `-y, --yes` | Skip confirmation prompts |
| `--dry-run` | Print intent without sending the write action |
| Flag | Description |
| ---------------------------------------- | --------------------------------------------------------- |
| `--output <format>` | Output format: `table`, `json`, `tsv` |
| `--json` | Shortcut for JSON output |
| `--fields <list>` | Comma-separated output field filter |
| `--network <network>` | Override `TRON_NETWORK` |
| `-k, --private-key <key>` | Provide a private key for this invocation only |
| `-m, --mnemonic <phrase>` | Provide a mnemonic for this invocation only |
| `-i, --mnemonic-account-index <index>` | Provide a mnemonic account index for this invocation only |
| `-p, --agent-wallet-password <password>` | Override `AGENT_WALLET_PASSWORD` for this invocation |
| `-d, --agent-wallet-dir <dir>` | Override `AGENT_WALLET_DIR` for this invocation |
| `-y, --yes` | Skip confirmation prompts |
| `--dry-run` | Print intent without sending the write action |

Examples:

Expand Down Expand Up @@ -418,8 +406,8 @@ npm run start -- --network nile swap TRX USDT 1000000

Set exactly one wallet source:

- `TRON_PRIVATE_KEY`
- `TRON_MNEMONIC`
- `AGENT_WALLET_PRIVATE_KEY`
- `AGENT_WALLET_MNEMONIC`
- `AGENT_WALLET_PASSWORD`

Or provide the equivalent root-level flag for that invocation.
Expand All @@ -436,10 +424,9 @@ Common causes:

Use `swap:quote` first and then retry with `--yes` only after the quote looks correct.


## Security Considerations

- Treat `TRON_PRIVATE_KEY`, `TRON_MNEMONIC`, and `AGENT_WALLET_PASSWORD` as secrets.
- Treat `AGENT_WALLET_PRIVATE_KEY`, `AGENT_WALLET_MNEMONIC`, and `AGENT_WALLET_PASSWORD` as secrets.
- Prefer environment variables over command-line wallet flags when possible, because shell history and process lists may expose secrets.
- Use a dedicated wallet for automation instead of a primary treasury wallet.
- Run `--dry-run` before high-value writes.
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bankofai/sun-cli",
"version": "1.0.1",
"version": "1.0.2",
"description": "CLI tool for SUN.IO / SUNSWAP on TRON — for humans and AI agents",
"main": "dist/bin.js",
"type": "commonjs",
Expand Down Expand Up @@ -41,7 +41,7 @@
"utf-8-validate": "5.0.10"
},
"dependencies": {
"@bankofai/agent-wallet": "^2.2.1",
"@bankofai/agent-wallet": "^2.3.0",
"@bankofai/sun-kit": "^1.0.0",
"@scure/bip32": "^2.0.1",
"@scure/bip39": "^2.0.1",
Expand Down
10 changes: 6 additions & 4 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import { registerFarmCommands } from './commands/farm'
import { registerLiquidityCommands } from './commands/liquidity'
import { registerContractCommands } from './commands/contract'

const { version } = require('../package.json') as { version: string }

const program = new Command()

program
.name('sun')
.description('CLI for SUN.IO / SUNSWAP on TRON — for humans and AI agents')
.version('1.0.0')
.version(version)
.option('--output <format>', 'Output format: table, json, tsv', 'table')
.option('--json', 'Shorthand for --output json', false)
.option('--fields <fields>', 'Comma-separated fields to include in output')
Expand Down Expand Up @@ -54,10 +56,10 @@ program
if (rootOpts.yes) setAutoConfirm(true)
if (rootOpts.dryRun) setDryRun(true)
if (rootOpts.network) process.env.TRON_NETWORK = rootOpts.network
if (rootOpts.privateKey) process.env.TRON_PRIVATE_KEY = rootOpts.privateKey
if (rootOpts.mnemonic) process.env.TRON_MNEMONIC = rootOpts.mnemonic
if (rootOpts.privateKey) process.env.AGENT_WALLET_PRIVATE_KEY = rootOpts.privateKey
if (rootOpts.mnemonic) process.env.AGENT_WALLET_MNEMONIC = rootOpts.mnemonic
if (rootOpts.mnemonicAccountIndex) {
process.env.TRON_MNEMONIC_ACCOUNT_INDEX = rootOpts.mnemonicAccountIndex
process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX = rootOpts.mnemonicAccountIndex
}
if (rootOpts.agentWalletPassword) {
process.env.AGENT_WALLET_PASSWORD = rootOpts.agentWalletPassword
Expand Down
2 changes: 1 addition & 1 deletion src/commands/liquidity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Command } from 'commander'
import { getNetwork } from '../lib/context'
import { writeAction, readAction } from '../lib/command'
import { printKeyValue, withSpinner } from '../lib/output'
import { withSpinner } from '../lib/output'
import { resolveTokenAddress, getSymbolOrAddress } from '../lib/tokens'
import {
SUNSWAP_V2_MAINNET_ROUTER,
Expand Down
7 changes: 0 additions & 7 deletions src/lib/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,6 @@ function getTronscanBaseUrl(network?: string): string | null {
}
}

type BroadcastResult = {
txid?: string
txID?: string
network?: string
tronscanUrl?: string
}

function attachExplorerLink<T>(
result: T,
fallbackNetwork?: string,
Expand Down
48 changes: 18 additions & 30 deletions src/lib/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,35 @@
import type { Wallet } from '@bankofai/sun-kit'
import { createReadonlyTronWeb } from '@bankofai/sun-kit'
import { resolveWalletProvider, type BaseWallet, type Eip712Capable } from '@bankofai/agent-wallet'
import {
resolveWalletProvider,
type Wallet as BaseWallet,
type Eip712Capable,
} from '@bankofai/agent-wallet'
import { TronWeb } from 'tronweb'

export type { Wallet }

let _wallet: Wallet | null = null

export async function initWallet(): Promise<void> {
const privateKey =
process.env.AGENT_WALLET_PRIVATE_KEY?.trim() || process.env.TRON_PRIVATE_KEY?.trim() || ''
const mnemonic =
process.env.AGENT_WALLET_MNEMONIC?.trim() || process.env.TRON_MNEMONIC?.trim() || ''
const accountIndex =
process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX?.trim() ||
process.env.TRON_MNEMONIC_ACCOUNT_INDEX?.trim() ||
''
const walletPassword = process.env.AGENT_WALLET_PASSWORD?.trim() ?? ''
const walletDir = process.env.AGENT_WALLET_DIR?.trim() ?? ''
const configuredModes = [privateKey, mnemonic, walletPassword].filter(Boolean).length

if (configuredModes > 1) {
throw new Error('Set only one of TRON_PRIVATE_KEY, TRON_MNEMONIC, or AGENT_WALLET_PASSWORD.')
}
if (configuredModes === 0) {
_wallet = null
try {
const provider = resolveWalletProvider({ network: 'tron' })
const activeWallet = await provider.getActiveWallet()
if (activeWallet === null || activeWallet === undefined) {
_wallet = null
return
}
_wallet = new AgentWalletAdapter(activeWallet)
} catch {
_wallet = null
return
}

process.env.AGENT_WALLET_PRIVATE_KEY = privateKey
process.env.AGENT_WALLET_MNEMONIC = mnemonic
process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX = accountIndex
process.env.AGENT_WALLET_PASSWORD = walletPassword
process.env.AGENT_WALLET_DIR = walletDir

const provider = resolveWalletProvider({ network: 'tron' })
const activeWallet = await provider.getActiveWallet()
_wallet = new AgentWalletAdapter(activeWallet)
}

export function getWallet(): Wallet {
if (!_wallet) {
throw new Error(
'No wallet configured. Set TRON_PRIVATE_KEY, TRON_MNEMONIC, or AGENT_WALLET_PASSWORD for agent-wallet.',
'No wallet configured. Set AGENT_WALLET_PRIVATE_KEY, AGENT_WALLET_MNEMONIC, or AGENT_WALLET_PASSWORD for agent-wallet.',
)
}
return _wallet
Expand Down Expand Up @@ -77,7 +64,8 @@ class AgentWalletAdapter implements Wallet {
? (tronWeb as any).address.fromHex(ownerHex)
: ownerAddress

;(tronWeb as any).defaultAddress = { hex: ownerHex, base58: ownerBase58 }
const tronWebWithDefaultAddress = tronWeb as any
tronWebWithDefaultAddress.defaultAddress = { hex: ownerHex, base58: ownerBase58 }
return tronWeb
}

Expand Down
4 changes: 2 additions & 2 deletions test/bin.test.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {};
//# sourceMappingURL=bin.test.d.ts.map
export {}
//# sourceMappingURL=bin.test.d.ts.map
Loading
Loading