diff --git a/README.md b/README.md index 8edb349..efc35fc 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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 @@ -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="" 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 @@ -333,19 +321,19 @@ sun contract send transfer --args '["TRecipient","1000000"]' - All commands inherit these root-level flags: -| Flag | Description | -| ---------------------------------------- | ---------------------------------------------------------- | -| `--output ` | Output format: `table`, `json`, `tsv` | -| `--json` | Shortcut for JSON output | -| `--fields ` | Comma-separated output field filter | -| `--network ` | Override `TRON_NETWORK` | -| `-k, --private-key ` | Override `TRON_PRIVATE_KEY` for this invocation | -| `-m, --mnemonic ` | Override `TRON_MNEMONIC` for this invocation | -| `-i, --mnemonic-account-index ` | Override `TRON_MNEMONIC_ACCOUNT_INDEX` for this invocation | -| `-p, --agent-wallet-password ` | Override `AGENT_WALLET_PASSWORD` for this invocation | -| `-d, --agent-wallet-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 ` | Output format: `table`, `json`, `tsv` | +| `--json` | Shortcut for JSON output | +| `--fields ` | Comma-separated output field filter | +| `--network ` | Override `TRON_NETWORK` | +| `-k, --private-key ` | Provide a private key for this invocation only | +| `-m, --mnemonic ` | Provide a mnemonic for this invocation only | +| `-i, --mnemonic-account-index ` | Provide a mnemonic account index for this invocation only | +| `-p, --agent-wallet-password ` | Override `AGENT_WALLET_PASSWORD` for this invocation | +| `-d, --agent-wallet-dir ` | Override `AGENT_WALLET_DIR` for this invocation | +| `-y, --yes` | Skip confirmation prompts | +| `--dry-run` | Print intent without sending the write action | Examples: @@ -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. @@ -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. diff --git a/package-lock.json b/package-lock.json index 79da1e2..366ffde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@bankofai/sun-cli", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bankofai/sun-cli", - "version": "1.0.1", + "version": "1.0.2", "license": "MIT", "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", @@ -546,9 +546,9 @@ } }, "node_modules/@bankofai/agent-wallet": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@bankofai/agent-wallet/-/agent-wallet-2.2.1.tgz", - "integrity": "sha512-397cAkV45vl+qyewK2dYerEOEV0NR1CtazUakhkbywu5pHg6Of/2/IGnmyZiVPYkSUYgdLChX7gA9H8zDwAGhQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@bankofai/agent-wallet/-/agent-wallet-2.3.0.tgz", + "integrity": "sha512-Jezo0ffhZrsF0HQMV74wTJlLUtHoY4d7TeYbjqjkWketCqBdhiX9/90hS4qwk99QZwnbt+1HRUschOaSA1wkRw==", "license": "MIT", "dependencies": { "@inquirer/prompts": "^8.3.0", diff --git a/package.json b/package.json index 871a16f..fba9eaa 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", diff --git a/src/bin.ts b/src/bin.ts index 068678b..0cd753c 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -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 ', 'Output format: table, json, tsv', 'table') .option('--json', 'Shorthand for --output json', false) .option('--fields ', 'Comma-separated fields to include in output') @@ -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 diff --git a/src/commands/liquidity.ts b/src/commands/liquidity.ts index b844ba2..ec9cae4 100644 --- a/src/commands/liquidity.ts +++ b/src/commands/liquidity.ts @@ -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, diff --git a/src/lib/command.ts b/src/lib/command.ts index 8c6d591..771cfb5 100644 --- a/src/lib/command.ts +++ b/src/lib/command.ts @@ -33,13 +33,6 @@ function getTronscanBaseUrl(network?: string): string | null { } } -type BroadcastResult = { - txid?: string - txID?: string - network?: string - tronscanUrl?: string -} - function attachExplorerLink( result: T, fallbackNetwork?: string, diff --git a/src/lib/wallet.ts b/src/lib/wallet.ts index 28413fe..b05764a 100644 --- a/src/lib/wallet.ts +++ b/src/lib/wallet.ts @@ -1,6 +1,10 @@ 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 } @@ -8,41 +12,24 @@ export type { Wallet } let _wallet: Wallet | null = null export async function initWallet(): Promise { - 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 @@ -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 } diff --git a/test/bin.test.d.ts b/test/bin.test.d.ts index 90b71ce..a72db14 100644 --- a/test/bin.test.d.ts +++ b/test/bin.test.d.ts @@ -1,2 +1,2 @@ -export {}; -//# sourceMappingURL=bin.test.d.ts.map \ No newline at end of file +export {} +//# sourceMappingURL=bin.test.d.ts.map diff --git a/test/bin.test.js b/test/bin.test.js index ba3cd5b..732e9dc 100644 --- a/test/bin.test.js +++ b/test/bin.test.js @@ -1,107 +1,106 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) describe('bin root wallet flags', () => { - const originalArgv = process.argv; - const originalEnv = process.env; - beforeEach(() => { - jest.resetModules(); - jest.clearAllMocks(); - process.argv = [...originalArgv]; - process.env = { ...originalEnv }; - delete process.env.TRON_PRIVATE_KEY; - delete process.env.TRON_MNEMONIC; - delete process.env.TRON_MNEMONIC_ACCOUNT_INDEX; - delete process.env.AGENT_WALLET_PASSWORD; - delete process.env.AGENT_WALLET_DIR; - }); - afterAll(() => { - process.argv = originalArgv; - process.env = originalEnv; - }); - function mockBinWithWalletCommand(onRun) { - const completed = new Promise((resolve, reject) => { - const registerWalletCommands = (program) => { - program - .command('wallet') - .command('address') - .action(async () => { - try { - await onRun(); - resolve(); - } - catch (err) { - reject(err); - } - }); - }; - jest.doMock('../src/commands/wallet', () => ({ - registerWalletCommands, - })); - const noop = () => undefined; - jest.doMock('../src/commands/price', () => ({ registerPriceCommand: noop })); - jest.doMock('../src/commands/swap', () => ({ registerSwapCommands: noop })); - jest.doMock('../src/commands/token', () => ({ registerTokenCommands: noop })); - jest.doMock('../src/commands/pool', () => ({ registerPoolCommands: noop })); - jest.doMock('../src/commands/protocol', () => ({ registerProtocolCommands: noop })); - jest.doMock('../src/commands/tx', () => ({ registerTxCommands: noop })); - jest.doMock('../src/commands/position', () => ({ registerPositionCommands: noop })); - jest.doMock('../src/commands/pair', () => ({ registerPairCommands: noop })); - jest.doMock('../src/commands/farm', () => ({ registerFarmCommands: noop })); - jest.doMock('../src/commands/liquidity', () => ({ registerLiquidityCommands: noop })); - jest.doMock('../src/commands/contract', () => ({ registerContractCommands: noop })); - require('../src/bin'); - }); - return completed; - } - it('maps root wallet flags into env for the current invocation', async () => { - process.argv = [ - 'node', - 'src/bin.ts', - '-k', - 'flag-private-key', - '-i', - '7', - '-p', - 'flag-password', - '-d', - '/tmp/flag-wallet', - 'wallet', - 'address', - ]; - await mockBinWithWalletCommand(() => { - expect(process.env.TRON_PRIVATE_KEY).toBe('flag-private-key'); - expect(process.env.TRON_MNEMONIC_ACCOUNT_INDEX).toBe('7'); - expect(process.env.AGENT_WALLET_PASSWORD).toBe('flag-password'); - expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/flag-wallet'); - }); - }); - it('lets root wallet flags override existing env values', async () => { - process.env.TRON_PRIVATE_KEY = 'env-private-key'; - process.env.TRON_MNEMONIC = 'env mnemonic'; - process.env.TRON_MNEMONIC_ACCOUNT_INDEX = '1'; - process.env.AGENT_WALLET_PASSWORD = 'env-password'; - process.env.AGENT_WALLET_DIR = '/tmp/env-wallet'; - process.argv = [ - 'node', - 'src/bin.ts', - '-m', - 'flag mnemonic', - '-i', - '3', - '-p', - 'flag-password', - '-d', - '/tmp/flag-wallet', - 'wallet', - 'address', - ]; - await mockBinWithWalletCommand(() => { - expect(process.env.TRON_PRIVATE_KEY).toBe('env-private-key'); - expect(process.env.TRON_MNEMONIC).toBe('flag mnemonic'); - expect(process.env.TRON_MNEMONIC_ACCOUNT_INDEX).toBe('3'); - expect(process.env.AGENT_WALLET_PASSWORD).toBe('flag-password'); - expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/flag-wallet'); - }); - }); -}); -//# sourceMappingURL=bin.test.js.map \ No newline at end of file + const originalArgv = process.argv + const originalEnv = process.env + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + process.argv = [...originalArgv] + process.env = { ...originalEnv } + delete process.env.AGENT_WALLET_PRIVATE_KEY + delete process.env.AGENT_WALLET_MNEMONIC + delete process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX + delete process.env.AGENT_WALLET_PASSWORD + delete process.env.AGENT_WALLET_DIR + }) + afterAll(() => { + process.argv = originalArgv + process.env = originalEnv + }) + function mockBinWithWalletCommand(onRun) { + const completed = new Promise((resolve, reject) => { + const registerWalletCommands = (program) => { + program + .command('wallet') + .command('address') + .action(async () => { + try { + await onRun() + resolve() + } catch (err) { + reject(err) + } + }) + } + jest.doMock('../src/commands/wallet', () => ({ + registerWalletCommands, + })) + const noop = () => undefined + jest.doMock('../src/commands/price', () => ({ registerPriceCommand: noop })) + jest.doMock('../src/commands/swap', () => ({ registerSwapCommands: noop })) + jest.doMock('../src/commands/token', () => ({ registerTokenCommands: noop })) + jest.doMock('../src/commands/pool', () => ({ registerPoolCommands: noop })) + jest.doMock('../src/commands/protocol', () => ({ registerProtocolCommands: noop })) + jest.doMock('../src/commands/tx', () => ({ registerTxCommands: noop })) + jest.doMock('../src/commands/position', () => ({ registerPositionCommands: noop })) + jest.doMock('../src/commands/pair', () => ({ registerPairCommands: noop })) + jest.doMock('../src/commands/farm', () => ({ registerFarmCommands: noop })) + jest.doMock('../src/commands/liquidity', () => ({ registerLiquidityCommands: noop })) + jest.doMock('../src/commands/contract', () => ({ registerContractCommands: noop })) + require('../src/bin') + }) + return completed + } + it('maps root wallet flags into env for the current invocation', async () => { + process.argv = [ + 'node', + 'src/bin.ts', + '-k', + 'flag-private-key', + '-i', + '7', + '-p', + 'flag-password', + '-d', + '/tmp/flag-wallet', + 'wallet', + 'address', + ] + await mockBinWithWalletCommand(() => { + expect(process.env.AGENT_WALLET_PRIVATE_KEY).toBe('flag-private-key') + expect(process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX).toBe('7') + expect(process.env.AGENT_WALLET_PASSWORD).toBe('flag-password') + expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/flag-wallet') + }) + }) + it('lets root wallet flags override existing env values', async () => { + process.env.AGENT_WALLET_PRIVATE_KEY = 'env-private-key' + process.env.AGENT_WALLET_MNEMONIC = 'env mnemonic' + process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX = '1' + process.env.AGENT_WALLET_PASSWORD = 'env-password' + process.env.AGENT_WALLET_DIR = '/tmp/env-wallet' + process.argv = [ + 'node', + 'src/bin.ts', + '-m', + 'flag mnemonic', + '-i', + '3', + '-p', + 'flag-password', + '-d', + '/tmp/flag-wallet', + 'wallet', + 'address', + ] + await mockBinWithWalletCommand(() => { + expect(process.env.AGENT_WALLET_PRIVATE_KEY).toBe('env-private-key') + expect(process.env.AGENT_WALLET_MNEMONIC).toBe('flag mnemonic') + expect(process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX).toBe('3') + expect(process.env.AGENT_WALLET_PASSWORD).toBe('flag-password') + expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/flag-wallet') + }) + }) +}) +//# sourceMappingURL=bin.test.js.map diff --git a/test/bin.test.ts b/test/bin.test.ts index 27bc825..1fb554a 100644 --- a/test/bin.test.ts +++ b/test/bin.test.ts @@ -9,9 +9,9 @@ describe('bin root wallet flags', () => { jest.clearAllMocks() process.argv = [...originalArgv] process.env = { ...originalEnv } - delete process.env.TRON_PRIVATE_KEY - delete process.env.TRON_MNEMONIC - delete process.env.TRON_MNEMONIC_ACCOUNT_INDEX + delete process.env.AGENT_WALLET_PRIVATE_KEY + delete process.env.AGENT_WALLET_MNEMONIC + delete process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX delete process.env.AGENT_WALLET_PASSWORD delete process.env.AGENT_WALLET_DIR }) @@ -77,17 +77,17 @@ describe('bin root wallet flags', () => { ] await mockBinWithWalletCommand(() => { - expect(process.env.TRON_PRIVATE_KEY).toBe('flag-private-key') - expect(process.env.TRON_MNEMONIC_ACCOUNT_INDEX).toBe('7') + expect(process.env.AGENT_WALLET_PRIVATE_KEY).toBe('flag-private-key') + expect(process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX).toBe('7') expect(process.env.AGENT_WALLET_PASSWORD).toBe('flag-password') expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/flag-wallet') }) }) it('lets root wallet flags override existing env values', async () => { - process.env.TRON_PRIVATE_KEY = 'env-private-key' - process.env.TRON_MNEMONIC = 'env mnemonic' - process.env.TRON_MNEMONIC_ACCOUNT_INDEX = '1' + process.env.AGENT_WALLET_PRIVATE_KEY = 'env-private-key' + process.env.AGENT_WALLET_MNEMONIC = 'env mnemonic' + process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX = '1' process.env.AGENT_WALLET_PASSWORD = 'env-password' process.env.AGENT_WALLET_DIR = '/tmp/env-wallet' @@ -107,9 +107,9 @@ describe('bin root wallet flags', () => { ] await mockBinWithWalletCommand(() => { - expect(process.env.TRON_PRIVATE_KEY).toBe('env-private-key') - expect(process.env.TRON_MNEMONIC).toBe('flag mnemonic') - expect(process.env.TRON_MNEMONIC_ACCOUNT_INDEX).toBe('3') + expect(process.env.AGENT_WALLET_PRIVATE_KEY).toBe('env-private-key') + expect(process.env.AGENT_WALLET_MNEMONIC).toBe('flag mnemonic') + expect(process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX).toBe('3') expect(process.env.AGENT_WALLET_PASSWORD).toBe('flag-password') expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/flag-wallet') }) diff --git a/test/commands/registration.test.d.ts b/test/commands/registration.test.d.ts index 480e9a5..f8590f7 100644 --- a/test/commands/registration.test.d.ts +++ b/test/commands/registration.test.d.ts @@ -1,2 +1,2 @@ -export {}; -//# sourceMappingURL=registration.test.d.ts.map \ No newline at end of file +export {} +//# sourceMappingURL=registration.test.d.ts.map diff --git a/test/commands/registration.test.js b/test/commands/registration.test.js index fb4b0d2..34f0bee 100644 --- a/test/commands/registration.test.js +++ b/test/commands/registration.test.js @@ -1,99 +1,98 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const commander_1 = require("commander"); -const wallet_1 = require("../../src/commands/wallet"); -const price_1 = require("../../src/commands/price"); -const swap_1 = require("../../src/commands/swap"); -const token_1 = require("../../src/commands/token"); -const pool_1 = require("../../src/commands/pool"); -const protocol_1 = require("../../src/commands/protocol"); -const tx_1 = require("../../src/commands/tx"); -const position_1 = require("../../src/commands/position"); -const pair_1 = require("../../src/commands/pair"); -const farm_1 = require("../../src/commands/farm"); -const liquidity_1 = require("../../src/commands/liquidity"); -const contract_1 = require("../../src/commands/contract"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const commander_1 = require('commander') +const wallet_1 = require('../../src/commands/wallet') +const price_1 = require('../../src/commands/price') +const swap_1 = require('../../src/commands/swap') +const token_1 = require('../../src/commands/token') +const pool_1 = require('../../src/commands/pool') +const protocol_1 = require('../../src/commands/protocol') +const tx_1 = require('../../src/commands/tx') +const position_1 = require('../../src/commands/position') +const pair_1 = require('../../src/commands/pair') +const farm_1 = require('../../src/commands/farm') +const liquidity_1 = require('../../src/commands/liquidity') +const contract_1 = require('../../src/commands/contract') function getCommandNames(program) { - return program.commands.map((cmd) => cmd.name()); + return program.commands.map((cmd) => cmd.name()) } function getSubcommandNames(program, parentName) { - const parent = program.commands.find((c) => c.name() === parentName); - if (!parent) - return []; - return parent.commands.map((cmd) => cmd.name()); + const parent = program.commands.find((c) => c.name() === parentName) + if (!parent) return [] + return parent.commands.map((cmd) => cmd.name()) } describe('command registration', () => { - let program; - beforeEach(() => { - program = new commander_1.Command(); - program.exitOverride(); // prevent process.exit - }); - it('registers all top-level command groups', () => { - (0, wallet_1.registerWalletCommands)(program); - (0, price_1.registerPriceCommand)(program); - (0, swap_1.registerSwapCommands)(program); - (0, token_1.registerTokenCommands)(program); - (0, pool_1.registerPoolCommands)(program); - (0, protocol_1.registerProtocolCommands)(program); - (0, tx_1.registerTxCommands)(program); - (0, position_1.registerPositionCommands)(program); - (0, pair_1.registerPairCommands)(program); - (0, farm_1.registerFarmCommands)(program); - (0, liquidity_1.registerLiquidityCommands)(program); - (0, contract_1.registerContractCommands)(program); - const names = getCommandNames(program); - expect(names).toContain('wallet'); - expect(names).toContain('price'); - expect(names).toContain('swap'); - expect(names).toContain('token'); - expect(names).toContain('pool'); - expect(names).toContain('protocol'); - expect(names).toContain('tx'); - expect(names).toContain('position'); - expect(names).toContain('pair'); - expect(names).toContain('farm'); - expect(names).toContain('liquidity'); - expect(names).toContain('contract'); - }); - it('registers wallet subcommands', () => { - (0, wallet_1.registerWalletCommands)(program); - const subs = getSubcommandNames(program, 'wallet'); - expect(subs).toContain('address'); - expect(subs).toContain('balances'); - }); - it('registers liquidity subcommands including V3 collect and V4', () => { - (0, liquidity_1.registerLiquidityCommands)(program); - const subs = getSubcommandNames(program, 'liquidity'); - // V2 - expect(subs).toContain('v2:add'); - expect(subs).toContain('v2:remove'); - // V3 - expect(subs).toContain('v3:mint'); - expect(subs).toContain('v3:increase'); - expect(subs).toContain('v3:decrease'); - expect(subs).toContain('v3:collect'); - // V4 - expect(subs).toContain('v4:mint'); - expect(subs).toContain('v4:increase'); - expect(subs).toContain('v4:decrease'); - expect(subs).toContain('v4:collect'); - expect(subs).toContain('v4:info'); - }); - it('registers pool subcommands', () => { - (0, pool_1.registerPoolCommands)(program); - const subs = getSubcommandNames(program, 'pool'); - expect(subs).toContain('list'); - expect(subs).toContain('search'); - expect(subs).toContain('top-apy'); - expect(subs).toContain('hooks'); - expect(subs).toContain('vol-history'); - expect(subs).toContain('liq-history'); - }); - it('registers contract subcommands', () => { - (0, contract_1.registerContractCommands)(program); - const subs = getSubcommandNames(program, 'contract'); - expect(subs).toContain('read'); - expect(subs).toContain('send'); - }); -}); -//# sourceMappingURL=registration.test.js.map \ No newline at end of file + let program + beforeEach(() => { + program = new commander_1.Command() + program.exitOverride() // prevent process.exit + }) + it('registers all top-level command groups', () => { + ;(0, wallet_1.registerWalletCommands)(program) + ;(0, price_1.registerPriceCommand)(program) + ;(0, swap_1.registerSwapCommands)(program) + ;(0, token_1.registerTokenCommands)(program) + ;(0, pool_1.registerPoolCommands)(program) + ;(0, protocol_1.registerProtocolCommands)(program) + ;(0, tx_1.registerTxCommands)(program) + ;(0, position_1.registerPositionCommands)(program) + ;(0, pair_1.registerPairCommands)(program) + ;(0, farm_1.registerFarmCommands)(program) + ;(0, liquidity_1.registerLiquidityCommands)(program) + ;(0, contract_1.registerContractCommands)(program) + const names = getCommandNames(program) + expect(names).toContain('wallet') + expect(names).toContain('price') + expect(names).toContain('swap') + expect(names).toContain('token') + expect(names).toContain('pool') + expect(names).toContain('protocol') + expect(names).toContain('tx') + expect(names).toContain('position') + expect(names).toContain('pair') + expect(names).toContain('farm') + expect(names).toContain('liquidity') + expect(names).toContain('contract') + }) + it('registers wallet subcommands', () => { + ;(0, wallet_1.registerWalletCommands)(program) + const subs = getSubcommandNames(program, 'wallet') + expect(subs).toContain('address') + expect(subs).toContain('balances') + }) + it('registers liquidity subcommands including V3 collect and V4', () => { + ;(0, liquidity_1.registerLiquidityCommands)(program) + const subs = getSubcommandNames(program, 'liquidity') + // V2 + expect(subs).toContain('v2:add') + expect(subs).toContain('v2:remove') + // V3 + expect(subs).toContain('v3:mint') + expect(subs).toContain('v3:increase') + expect(subs).toContain('v3:decrease') + expect(subs).toContain('v3:collect') + // V4 + expect(subs).toContain('v4:mint') + expect(subs).toContain('v4:increase') + expect(subs).toContain('v4:decrease') + expect(subs).toContain('v4:collect') + expect(subs).toContain('v4:info') + }) + it('registers pool subcommands', () => { + ;(0, pool_1.registerPoolCommands)(program) + const subs = getSubcommandNames(program, 'pool') + expect(subs).toContain('list') + expect(subs).toContain('search') + expect(subs).toContain('top-apy') + expect(subs).toContain('hooks') + expect(subs).toContain('vol-history') + expect(subs).toContain('liq-history') + }) + it('registers contract subcommands', () => { + ;(0, contract_1.registerContractCommands)(program) + const subs = getSubcommandNames(program, 'contract') + expect(subs).toContain('read') + expect(subs).toContain('send') + }) +}) +//# sourceMappingURL=registration.test.js.map diff --git a/test/lib/confirm.test.d.ts b/test/lib/confirm.test.d.ts index c720113..e9b73f7 100644 --- a/test/lib/confirm.test.d.ts +++ b/test/lib/confirm.test.d.ts @@ -1,2 +1,2 @@ -export {}; -//# sourceMappingURL=confirm.test.d.ts.map \ No newline at end of file +export {} +//# sourceMappingURL=confirm.test.d.ts.map diff --git a/test/lib/confirm.test.js b/test/lib/confirm.test.js index b96dece..f2f5b16 100644 --- a/test/lib/confirm.test.js +++ b/test/lib/confirm.test.js @@ -1,24 +1,24 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const confirm_1 = require("../../src/lib/confirm"); -const output_1 = require("../../src/lib/output"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const confirm_1 = require('../../src/lib/confirm') +const output_1 = require('../../src/lib/output') describe('confirm', () => { - afterEach(() => { - (0, confirm_1.setAutoConfirm)(false); - (0, output_1.setJsonMode)(false); - }); - it('returns true when --yes flag is set', async () => { - (0, confirm_1.setAutoConfirm)(true); - expect(await (0, confirm_1.confirm)('Do this?')).toBe(true); - }); - it('returns true when --json mode is active', async () => { - (0, output_1.setJsonMode)(true); - expect(await (0, confirm_1.confirm)('Do this?')).toBe(true); - }); - it('returns true when both --yes and --json are set', async () => { - (0, confirm_1.setAutoConfirm)(true); - (0, output_1.setJsonMode)(true); - expect(await (0, confirm_1.confirm)('Do this?')).toBe(true); - }); -}); -//# sourceMappingURL=confirm.test.js.map \ No newline at end of file + afterEach(() => { + ;(0, confirm_1.setAutoConfirm)(false) + ;(0, output_1.setJsonMode)(false) + }) + it('returns true when --yes flag is set', async () => { + ;(0, confirm_1.setAutoConfirm)(true) + expect(await (0, confirm_1.confirm)('Do this?')).toBe(true) + }) + it('returns true when --json mode is active', async () => { + ;(0, output_1.setJsonMode)(true) + expect(await (0, confirm_1.confirm)('Do this?')).toBe(true) + }) + it('returns true when both --yes and --json are set', async () => { + ;(0, confirm_1.setAutoConfirm)(true) + ;(0, output_1.setJsonMode)(true) + expect(await (0, confirm_1.confirm)('Do this?')).toBe(true) + }) +}) +//# sourceMappingURL=confirm.test.js.map diff --git a/test/lib/context.test.d.ts b/test/lib/context.test.d.ts index f706774..eff5943 100644 --- a/test/lib/context.test.d.ts +++ b/test/lib/context.test.d.ts @@ -1 +1 @@ -//# sourceMappingURL=context.test.d.ts.map \ No newline at end of file +//# sourceMappingURL=context.test.d.ts.map diff --git a/test/lib/context.test.js b/test/lib/context.test.js index c7e1da2..43d6fcf 100644 --- a/test/lib/context.test.js +++ b/test/lib/context.test.js @@ -1,90 +1,92 @@ -"use strict"; +'use strict' describe('context', () => { - beforeEach(() => { - jest.resetModules(); - jest.clearAllMocks(); - delete process.env.TRON_NETWORK; - delete process.env.TRONGRID_API_KEY; - delete process.env.TRON_GRID_API_KEY; - delete process.env.TRON_RPC_URL; - }); - function loadContextModule(options) { - const wallet = options?.wallet ?? { type: 'agent-wallet' }; - const initWallet = jest.fn().mockResolvedValue(undefined); - const getWallet = jest.fn().mockReturnValue(wallet); - const isWalletConfigured = jest.fn().mockReturnValue(options?.walletConfigured ?? true); - const SunAPI = jest.fn().mockImplementation(() => ({ kind: 'api-instance' })); - const SunKit = jest.fn().mockImplementation((config) => ({ kind: 'kit-instance', config })); - jest.doMock('../../src/lib/wallet', () => ({ - initWallet, - getWallet, - isWalletConfigured, - })); - jest.doMock('@bankofai/sun-kit', () => ({ - SunAPI, - SunKit, - })); - const contextModule = require('../../src/lib/context'); - return { - contextModule, - initWallet, - getWallet, - isWalletConfigured, - SunAPI, - SunKit, - wallet, - }; + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + delete process.env.TRON_NETWORK + delete process.env.TRONGRID_API_KEY + delete process.env.TRON_GRID_API_KEY + delete process.env.TRON_RPC_URL + }) + function loadContextModule(options) { + const wallet = options?.wallet ?? { type: 'agent-wallet' } + const initWallet = jest.fn().mockResolvedValue(undefined) + const getWallet = jest.fn().mockReturnValue(wallet) + const isWalletConfigured = jest.fn().mockReturnValue(options?.walletConfigured ?? true) + const SunAPI = jest.fn().mockImplementation(() => ({ kind: 'api-instance' })) + const SunKit = jest.fn().mockImplementation((config) => ({ kind: 'kit-instance', config })) + jest.doMock('../../src/lib/wallet', () => ({ + initWallet, + getWallet, + isWalletConfigured, + })) + jest.doMock('@bankofai/sun-kit', () => ({ + SunAPI, + SunKit, + })) + const contextModule = require('../../src/lib/context') + return { + contextModule, + initWallet, + getWallet, + isWalletConfigured, + SunAPI, + SunKit, + wallet, } - it('lazily initializes SunKit once and reuses the same instance', async () => { - process.env.TRON_NETWORK = 'nile'; - process.env.TRONGRID_API_KEY = 'grid-key'; - process.env.TRON_RPC_URL = 'https://rpc.local'; - const { contextModule, initWallet, getWallet, SunKit, wallet } = loadContextModule(); - const first = await contextModule.getKit(); - const second = await contextModule.getKit(); - expect(initWallet).toHaveBeenCalledTimes(1); - expect(getWallet).toHaveBeenCalledTimes(1); - expect(SunKit).toHaveBeenCalledTimes(1); - expect(first).toBe(second); - expect(first).toEqual({ - kind: 'kit-instance', - config: { - wallet, - network: 'nile', - tronGridApiKey: 'grid-key', - rpcUrl: 'https://rpc.local', - }, - }); - }); - it('creates SunKit without a wallet when none is configured', async () => { - process.env.TRON_GRID_API_KEY = 'fallback-key'; - const { contextModule, getWallet, SunKit } = loadContextModule({ - walletConfigured: false, - }); - const kit = await contextModule.getKit(); - expect(getWallet).not.toHaveBeenCalled(); - expect(SunKit).toHaveBeenCalledWith({ - wallet: undefined, - network: 'mainnet', - tronGridApiKey: 'fallback-key', - rpcUrl: undefined, - }); - expect(kit.config.wallet).toBeUndefined(); - }); - it('throws from ensureWallet when initialization completes without a wallet', async () => { - const { contextModule, initWallet, isWalletConfigured } = loadContextModule({ - walletConfigured: false, - }); - await expect(contextModule.ensureWallet()).rejects.toThrow('Wallet required. Set agent-wallet credentials before running this command.'); - expect(initWallet).toHaveBeenCalledTimes(1); - expect(isWalletConfigured).toHaveBeenCalledTimes(1); - }); - it('caches SunAPI instances', () => { - const { contextModule, SunAPI } = loadContextModule(); - const first = contextModule.getApi(); - const second = contextModule.getApi(); - expect(SunAPI).toHaveBeenCalledTimes(1); - expect(first).toBe(second); - }); -}); -//# sourceMappingURL=context.test.js.map \ No newline at end of file + } + it('lazily initializes SunKit once and reuses the same instance', async () => { + process.env.TRON_NETWORK = 'nile' + process.env.TRONGRID_API_KEY = 'grid-key' + process.env.TRON_RPC_URL = 'https://rpc.local' + const { contextModule, initWallet, getWallet, SunKit, wallet } = loadContextModule() + const first = await contextModule.getKit() + const second = await contextModule.getKit() + expect(initWallet).toHaveBeenCalledTimes(1) + expect(getWallet).toHaveBeenCalledTimes(1) + expect(SunKit).toHaveBeenCalledTimes(1) + expect(first).toBe(second) + expect(first).toEqual({ + kind: 'kit-instance', + config: { + wallet, + network: 'nile', + tronGridApiKey: 'grid-key', + rpcUrl: 'https://rpc.local', + }, + }) + }) + it('creates SunKit without a wallet when none is configured', async () => { + process.env.TRON_GRID_API_KEY = 'fallback-key' + const { contextModule, getWallet, SunKit } = loadContextModule({ + walletConfigured: false, + }) + const kit = await contextModule.getKit() + expect(getWallet).not.toHaveBeenCalled() + expect(SunKit).toHaveBeenCalledWith({ + wallet: undefined, + network: 'mainnet', + tronGridApiKey: 'fallback-key', + rpcUrl: undefined, + }) + expect(kit.config.wallet).toBeUndefined() + }) + it('throws from ensureWallet when initialization completes without a wallet', async () => { + const { contextModule, initWallet, isWalletConfigured } = loadContextModule({ + walletConfigured: false, + }) + await expect(contextModule.ensureWallet()).rejects.toThrow( + 'Wallet required. Set agent-wallet credentials before running this command.', + ) + expect(initWallet).toHaveBeenCalledTimes(1) + expect(isWalletConfigured).toHaveBeenCalledTimes(1) + }) + it('caches SunAPI instances', () => { + const { contextModule, SunAPI } = loadContextModule() + const first = contextModule.getApi() + const second = contextModule.getApi() + expect(SunAPI).toHaveBeenCalledTimes(1) + expect(first).toBe(second) + }) +}) +//# sourceMappingURL=context.test.js.map diff --git a/test/lib/output.test.d.ts b/test/lib/output.test.d.ts index 98bcb63..e677611 100644 --- a/test/lib/output.test.d.ts +++ b/test/lib/output.test.d.ts @@ -1,2 +1,2 @@ -export {}; -//# sourceMappingURL=output.test.d.ts.map \ No newline at end of file +export {} +//# sourceMappingURL=output.test.d.ts.map diff --git a/test/lib/output.test.js b/test/lib/output.test.js index 29f2c73..14462d0 100644 --- a/test/lib/output.test.js +++ b/test/lib/output.test.js @@ -1,126 +1,126 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const output_1 = require("../../src/lib/output"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const output_1 = require('../../src/lib/output') describe('filterFields', () => { - afterEach(() => (0, output_1.setFields)(null)); - it('returns original data when no fields are set', () => { - const data = { a: 1, b: 2, c: 3 }; - expect((0, output_1.filterFields)(data)).toEqual(data); - }); - it('filters object to only specified fields', () => { - (0, output_1.setFields)(['a', 'c']); - expect((0, output_1.filterFields)({ a: 1, b: 2, c: 3 })).toEqual({ a: 1, c: 3 }); - }); - it('filters each item in an array', () => { - (0, output_1.setFields)(['name']); - const data = [ - { name: 'Alice', age: 30 }, - { name: 'Bob', age: 25 }, - ]; - expect((0, output_1.filterFields)(data)).toEqual([{ name: 'Alice' }, { name: 'Bob' }]); - }); - it('returns primitive values unchanged', () => { - (0, output_1.setFields)(['a']); - expect((0, output_1.filterFields)('hello')).toBe('hello'); - expect((0, output_1.filterFields)(42)).toBe(42); - expect((0, output_1.filterFields)(null)).toBe(null); - }); - it('ignores fields that do not exist on the object', () => { - (0, output_1.setFields)(['x', 'y']); - expect((0, output_1.filterFields)({ a: 1, b: 2 })).toEqual({}); - }); -}); + afterEach(() => (0, output_1.setFields)(null)) + it('returns original data when no fields are set', () => { + const data = { a: 1, b: 2, c: 3 } + expect((0, output_1.filterFields)(data)).toEqual(data) + }) + it('filters object to only specified fields', () => { + ;(0, output_1.setFields)(['a', 'c']) + expect((0, output_1.filterFields)({ a: 1, b: 2, c: 3 })).toEqual({ a: 1, c: 3 }) + }) + it('filters each item in an array', () => { + ;(0, output_1.setFields)(['name']) + const data = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + ] + expect((0, output_1.filterFields)(data)).toEqual([{ name: 'Alice' }, { name: 'Bob' }]) + }) + it('returns primitive values unchanged', () => { + ;(0, output_1.setFields)(['a']) + expect((0, output_1.filterFields)('hello')).toBe('hello') + expect((0, output_1.filterFields)(42)).toBe(42) + expect((0, output_1.filterFields)(null)).toBe(null) + }) + it('ignores fields that do not exist on the object', () => { + ;(0, output_1.setFields)(['x', 'y']) + expect((0, output_1.filterFields)({ a: 1, b: 2 })).toEqual({}) + }) +}) describe('extractList', () => { - it('returns arrays directly', () => { - expect((0, output_1.extractList)([1, 2, 3])).toEqual([1, 2, 3]); - }); - it('extracts .list wrapper', () => { - expect((0, output_1.extractList)({ list: [1, 2] })).toEqual([1, 2]); - }); - it('extracts .rows wrapper', () => { - expect((0, output_1.extractList)({ rows: [1, 2] })).toEqual([1, 2]); - }); - it('extracts .data wrapper', () => { - expect((0, output_1.extractList)({ data: [1, 2] })).toEqual([1, 2]); - }); - it('extracts .tokens wrapper', () => { - expect((0, output_1.extractList)({ tokens: [{ a: 1 }] })).toEqual([{ a: 1 }]); - }); - it('extracts .pools wrapper', () => { - expect((0, output_1.extractList)({ pools: [{ a: 1 }] })).toEqual([{ a: 1 }]); - }); - it('returns null for non-list objects', () => { - expect((0, output_1.extractList)({ foo: 'bar' })).toBeNull(); - }); - it('returns null for primitives', () => { - expect((0, output_1.extractList)('hello')).toBeNull(); - expect((0, output_1.extractList)(42)).toBeNull(); - }); -}); + it('returns arrays directly', () => { + expect((0, output_1.extractList)([1, 2, 3])).toEqual([1, 2, 3]) + }) + it('extracts .list wrapper', () => { + expect((0, output_1.extractList)({ list: [1, 2] })).toEqual([1, 2]) + }) + it('extracts .rows wrapper', () => { + expect((0, output_1.extractList)({ rows: [1, 2] })).toEqual([1, 2]) + }) + it('extracts .data wrapper', () => { + expect((0, output_1.extractList)({ data: [1, 2] })).toEqual([1, 2]) + }) + it('extracts .tokens wrapper', () => { + expect((0, output_1.extractList)({ tokens: [{ a: 1 }] })).toEqual([{ a: 1 }]) + }) + it('extracts .pools wrapper', () => { + expect((0, output_1.extractList)({ pools: [{ a: 1 }] })).toEqual([{ a: 1 }]) + }) + it('returns null for non-list objects', () => { + expect((0, output_1.extractList)({ foo: 'bar' })).toBeNull() + }) + it('returns null for primitives', () => { + expect((0, output_1.extractList)('hello')).toBeNull() + expect((0, output_1.extractList)(42)).toBeNull() + }) +}) describe('outputJson compact format', () => { - let stdoutData; - beforeEach(() => { - stdoutData = ''; - jest.spyOn(process.stdout, 'write').mockImplementation((chunk) => { - stdoutData += chunk; - return true; - }); - (0, output_1.setJsonMode)(true); - (0, output_1.setFields)(null); - }); - afterEach(() => { - jest.restoreAllMocks(); - (0, output_1.setJsonMode)(false); - }); - it('outputs compact JSON without pretty-printing', () => { - (0, output_1.outputJson)({ key: 'value', nested: { a: 1 } }); - expect(stdoutData).toBe('{"key":"value","nested":{"a":1}}\n'); - // No spaces or newlines inside the JSON - expect(stdoutData).not.toContain(' '); - }); -}); + let stdoutData + beforeEach(() => { + stdoutData = '' + jest.spyOn(process.stdout, 'write').mockImplementation((chunk) => { + stdoutData += chunk + return true + }) + ;(0, output_1.setJsonMode)(true) + ;(0, output_1.setFields)(null) + }) + afterEach(() => { + jest.restoreAllMocks() + ;(0, output_1.setJsonMode)(false) + }) + it('outputs compact JSON without pretty-printing', () => { + ;(0, output_1.outputJson)({ key: 'value', nested: { a: 1 } }) + expect(stdoutData).toBe('{"key":"value","nested":{"a":1}}\n') + // No spaces or newlines inside the JSON + expect(stdoutData).not.toContain(' ') + }) +}) describe('outputError structured codes', () => { - let stdoutData; - beforeEach(() => { - stdoutData = ''; - jest.spyOn(process.stdout, 'write').mockImplementation((chunk) => { - stdoutData += chunk; - return true; - }); - (0, output_1.setJsonMode)(true); - }); - afterEach(() => { - jest.restoreAllMocks(); - (0, output_1.setJsonMode)(false); - process.exitCode = undefined; - }); - it('includes error code in JSON output', () => { - (0, output_1.outputError)('Wallet required', new Error('Set TRON_PRIVATE_KEY')); - const parsed = JSON.parse(stdoutData); - expect(parsed.code).toBe('WALLET_NOT_CONFIGURED'); - expect(parsed.error).toBe('Wallet required'); - expect(parsed.detail).toBe('Set TRON_PRIVATE_KEY'); - }); - it('uses error object code if available', () => { - const err = new Error('Pool not found'); - err.code = 'POOL_NOT_FOUND'; - (0, output_1.outputError)('Operation failed', err); - const parsed = JSON.parse(stdoutData); - expect(parsed.code).toBe('POOL_NOT_FOUND'); - }); - it('classifies network errors', () => { - (0, output_1.outputError)('Request failed', new Error('fetch failed: ECONNREFUSED')); - const parsed = JSON.parse(stdoutData); - expect(parsed.code).toBe('NETWORK_ERROR'); - }); - it('falls back to UNKNOWN_ERROR', () => { - (0, output_1.outputError)('Something went wrong'); - const parsed = JSON.parse(stdoutData); - expect(parsed.code).toBe('UNKNOWN_ERROR'); - }); - it('sets exit code to 1', () => { - (0, output_1.outputError)('fail'); - expect(process.exitCode).toBe(1); - }); -}); -//# sourceMappingURL=output.test.js.map \ No newline at end of file + let stdoutData + beforeEach(() => { + stdoutData = '' + jest.spyOn(process.stdout, 'write').mockImplementation((chunk) => { + stdoutData += chunk + return true + }) + ;(0, output_1.setJsonMode)(true) + }) + afterEach(() => { + jest.restoreAllMocks() + ;(0, output_1.setJsonMode)(false) + process.exitCode = undefined + }) + it('includes error code in JSON output', () => { + ;(0, output_1.outputError)('Wallet required', new Error('Set AGENT_WALLET_PRIVATE_KEY')) + const parsed = JSON.parse(stdoutData) + expect(parsed.code).toBe('WALLET_NOT_CONFIGURED') + expect(parsed.error).toBe('Wallet required') + expect(parsed.detail).toBe('Set AGENT_WALLET_PRIVATE_KEY') + }) + it('uses error object code if available', () => { + const err = new Error('Pool not found') + err.code = 'POOL_NOT_FOUND' + ;(0, output_1.outputError)('Operation failed', err) + const parsed = JSON.parse(stdoutData) + expect(parsed.code).toBe('POOL_NOT_FOUND') + }) + it('classifies network errors', () => { + ;(0, output_1.outputError)('Request failed', new Error('fetch failed: ECONNREFUSED')) + const parsed = JSON.parse(stdoutData) + expect(parsed.code).toBe('NETWORK_ERROR') + }) + it('falls back to UNKNOWN_ERROR', () => { + ;(0, output_1.outputError)('Something went wrong') + const parsed = JSON.parse(stdoutData) + expect(parsed.code).toBe('UNKNOWN_ERROR') + }) + it('sets exit code to 1', () => { + ;(0, output_1.outputError)('fail') + expect(process.exitCode).toBe(1) + }) +}) +//# sourceMappingURL=output.test.js.map diff --git a/test/lib/output.test.ts b/test/lib/output.test.ts index 794aa6e..f61477c 100644 --- a/test/lib/output.test.ts +++ b/test/lib/output.test.ts @@ -136,11 +136,11 @@ describe('outputError structured codes', () => { }) it('includes error code in JSON output', () => { - outputError('Wallet required', new Error('Set TRON_PRIVATE_KEY')) + outputError('Wallet required', new Error('Set AGENT_WALLET_PRIVATE_KEY')) const parsed = JSON.parse(stdoutData) expect(parsed.code).toBe('WALLET_NOT_CONFIGURED') expect(parsed.error).toBe('Wallet required') - expect(parsed.detail).toBe('Set TRON_PRIVATE_KEY') + expect(parsed.detail).toBe('Set AGENT_WALLET_PRIVATE_KEY') }) it('uses error object code if available', () => { diff --git a/test/lib/wallet.test.d.ts b/test/lib/wallet.test.d.ts index ba41dbe..e19d236 100644 --- a/test/lib/wallet.test.d.ts +++ b/test/lib/wallet.test.d.ts @@ -1 +1 @@ -//# sourceMappingURL=wallet.test.d.ts.map \ No newline at end of file +//# sourceMappingURL=wallet.test.d.ts.map diff --git a/test/lib/wallet.test.js b/test/lib/wallet.test.js index 63da063..309cea2 100644 --- a/test/lib/wallet.test.js +++ b/test/lib/wallet.test.js @@ -1,142 +1,162 @@ -"use strict"; +'use strict' describe('wallet', () => { - const originalEnv = process.env; - beforeEach(() => { - jest.resetModules(); - jest.clearAllMocks(); - process.env = { ...originalEnv }; - delete process.env.TRON_PRIVATE_KEY; - delete process.env.TRON_MNEMONIC; - delete process.env.TRON_MNEMONIC_ACCOUNT_INDEX; - delete process.env.AGENT_WALLET_PASSWORD; - delete process.env.AGENT_WALLET_DIR; - delete process.env.AGENT_WALLET_PRIVATE_KEY; - delete process.env.AGENT_WALLET_MNEMONIC; - delete process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX; - delete process.env.AGENT_WALLET_PASSWORD; - delete process.env.AGENT_WALLET_DIR; - }); - afterAll(() => { - process.env = originalEnv; - }); - function loadWalletModule(options) { - const activeWallet = options?.activeWallet ?? { - getAddress: jest.fn().mockResolvedValue('TWalletAddress'), - signTransaction: jest.fn().mockResolvedValue('{"txID":"signed"}'), - signMessage: jest.fn().mockResolvedValue('signed-message'), - signTypedData: jest.fn().mockResolvedValue('0xsignedtypeddata'), - }; - const tronWeb = options?.tronWeb ?? { - address: { - toHex: jest.fn().mockReturnValue('41abc'), - fromHex: jest.fn().mockReturnValue('TWalletAddress'), - }, - trx: { - sendRawTransaction: jest.fn().mockResolvedValue({ result: true, txid: 'tx-123' }), - }, - }; - const provider = { - getActiveWallet: jest.fn().mockResolvedValue(activeWallet), - }; - const resolveWalletProvider = jest.fn().mockReturnValue(provider); - const createReadonlyTronWeb = jest.fn().mockResolvedValue(tronWeb); - jest.doMock('@bankofai/agent-wallet', () => ({ - resolveWalletProvider, - })); - jest.doMock('@bankofai/sun-kit', () => ({ - createReadonlyTronWeb, - })); - const walletModule = require('../../src/lib/wallet'); - return { - walletModule, - activeWallet, - tronWeb, - provider, - resolveWalletProvider, - createReadonlyTronWeb, - }; + const originalEnv = process.env + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + process.env = { ...originalEnv } + delete process.env.AGENT_WALLET_PASSWORD + delete process.env.AGENT_WALLET_DIR + delete process.env.AGENT_WALLET_PRIVATE_KEY + delete process.env.AGENT_WALLET_MNEMONIC + delete process.env.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX + delete process.env.AGENT_WALLET_PASSWORD + delete process.env.AGENT_WALLET_DIR + }) + afterAll(() => { + process.env = originalEnv + }) + function loadWalletModule(options) { + const activeWallet = options?.activeWallet ?? { + getAddress: jest.fn().mockResolvedValue('TWalletAddress'), + signTransaction: jest.fn().mockResolvedValue('{"txID":"signed"}'), + signMessage: jest.fn().mockResolvedValue('signed-message'), + signTypedData: jest.fn().mockResolvedValue('0xsignedtypeddata'), } - it('leaves wallet unconfigured when no credentials are set', async () => { - const { walletModule, resolveWalletProvider } = loadWalletModule(); - await walletModule.initWallet(); - expect(walletModule.isWalletConfigured()).toBe(false); - expect(resolveWalletProvider).not.toHaveBeenCalled(); - expect(() => walletModule.getWallet()).toThrow('No wallet configured'); - }); - it('rejects multiple wallet configuration modes', async () => { - process.env.TRON_PRIVATE_KEY = 'pk'; - process.env.AGENT_WALLET_PASSWORD = 'pw'; - const { walletModule, resolveWalletProvider } = loadWalletModule(); - await expect(walletModule.initWallet()).rejects.toThrow('Set only one of TRON_PRIVATE_KEY, TRON_MNEMONIC, or AGENT_WALLET_PASSWORD.'); - expect(resolveWalletProvider).not.toHaveBeenCalled(); - }); - it('initializes agent-wallet from private key env and exposes address', async () => { - process.env.TRON_PRIVATE_KEY = 'private-key'; - process.env.AGENT_WALLET_DIR = '/tmp/agent-wallet'; - const { walletModule, resolveWalletProvider, provider } = loadWalletModule(); - await walletModule.initWallet(); - expect(resolveWalletProvider).toHaveBeenCalledWith({ network: 'tron' }); - expect(provider.getActiveWallet).toHaveBeenCalledTimes(1); - expect(process.env.AGENT_WALLET_PRIVATE_KEY).toBe('private-key'); - expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/agent-wallet'); - await expect(walletModule.getWalletAddress()).resolves.toBe('TWalletAddress'); - }); - it('builds tronWeb with the active wallet as default address', async () => { - process.env.AGENT_WALLET_PASSWORD = 'secret'; - const { walletModule, tronWeb, createReadonlyTronWeb } = loadWalletModule(); - await walletModule.initWallet(); - const wallet = walletModule.getWallet(); - const resolvedTronWeb = await wallet.getTronWeb('nile'); - expect(createReadonlyTronWeb).toHaveBeenCalledWith('nile'); - expect(resolvedTronWeb).toBe(tronWeb); - expect(tronWeb.address.toHex).toHaveBeenCalledWith('TWalletAddress'); - expect(tronWeb.address.fromHex).toHaveBeenCalledWith('41abc'); - expect(tronWeb.defaultAddress).toEqual({ - hex: '41abc', - base58: 'TWalletAddress', - }); - }); - it('signs, broadcasts, and normalizes typed-data signatures', async () => { - process.env.AGENT_WALLET_PASSWORD = 'secret'; - const { walletModule, activeWallet, tronWeb } = loadWalletModule({ - activeWallet: { - getAddress: jest.fn().mockResolvedValue('TWalletAddress'), - signTransaction: jest.fn().mockResolvedValue('{"txID":"signed","raw_data":{"x":1}}'), - signMessage: jest.fn().mockResolvedValue('signed-message'), - signTypedData: jest.fn().mockResolvedValue('0xdeadbeef'), - }, - tronWeb: { - address: { - toHex: jest.fn().mockReturnValue('41abc'), - fromHex: jest.fn().mockReturnValue('TWalletAddress'), - }, - trx: { - sendRawTransaction: jest.fn().mockResolvedValue({ result: true, txid: 'tx-999' }), - }, - }, - }); - await walletModule.initWallet(); - const wallet = walletModule.getWallet(); - await expect(wallet.signAndBroadcast({ transaction: { raw_data: { contract: [] } } }, 'mainnet')).resolves.toEqual({ result: true, txid: 'tx-999' }); - expect(activeWallet.signTransaction).toHaveBeenCalledWith({ raw_data: { contract: [] } }); - expect(tronWeb.trx.sendRawTransaction).toHaveBeenCalledWith({ - txID: 'signed', - raw_data: { x: 1 }, - }); - await expect(wallet.signTypedData('Permit', { name: 'Sun', chainId: 1, verifyingContract: 'TContract' }, { Permit: [{ name: 'owner', type: 'address' }] }, { owner: 'TWalletAddress' })).resolves.toBe('deadbeef'); - expect(activeWallet.signTypedData).toHaveBeenCalledWith({ - domain: { name: 'Sun', chainId: 1, verifyingContract: 'TContract' }, - types: { - EIP712Domain: [ - { name: 'name', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, - ], - Permit: [{ name: 'owner', type: 'address' }], - }, - primaryType: 'Permit', - message: { owner: 'TWalletAddress' }, - }); - }); -}); -//# sourceMappingURL=wallet.test.js.map \ No newline at end of file + const tronWeb = options?.tronWeb ?? { + address: { + toHex: jest.fn().mockReturnValue('41abc'), + fromHex: jest.fn().mockReturnValue('TWalletAddress'), + }, + trx: { + sendRawTransaction: jest.fn().mockResolvedValue({ result: true, txid: 'tx-123' }), + }, + } + const provider = { + getActiveWallet: options?.getActiveWalletError + ? jest.fn().mockRejectedValue(options.getActiveWalletError) + : jest + .fn() + .mockResolvedValue( + options?.getActiveWalletValue === undefined + ? activeWallet + : options.getActiveWalletValue, + ), + } + const resolveWalletProvider = jest.fn().mockReturnValue(provider) + const createReadonlyTronWeb = jest.fn().mockResolvedValue(tronWeb) + jest.doMock('@bankofai/agent-wallet', () => ({ + resolveWalletProvider, + })) + jest.doMock('@bankofai/sun-kit', () => ({ + createReadonlyTronWeb, + })) + const walletModule = require('../../src/lib/wallet') + return { + walletModule, + activeWallet, + tronWeb, + provider, + resolveWalletProvider, + createReadonlyTronWeb, + } + } + it('leaves wallet unconfigured when the wallet provider cannot resolve an active wallet', async () => { + const { walletModule, resolveWalletProvider, provider } = loadWalletModule({ + getActiveWalletError: new Error('No active wallet'), + }) + await walletModule.initWallet() + expect(walletModule.isWalletConfigured()).toBe(false) + expect(resolveWalletProvider).toHaveBeenCalledWith({ network: 'tron' }) + expect(provider.getActiveWallet).toHaveBeenCalledTimes(1) + expect(() => walletModule.getWallet()).toThrow('No wallet configured') + }) + it('leaves wallet unconfigured when the wallet provider returns null', async () => { + const { walletModule, resolveWalletProvider, provider } = loadWalletModule({ + getActiveWalletValue: null, + }) + await walletModule.initWallet() + expect(walletModule.isWalletConfigured()).toBe(false) + expect(resolveWalletProvider).toHaveBeenCalledWith({ network: 'tron' }) + expect(provider.getActiveWallet).toHaveBeenCalledTimes(1) + expect(() => walletModule.getWallet()).toThrow('No wallet configured') + }) + it('initializes agent-wallet and exposes address', async () => { + process.env.AGENT_WALLET_PRIVATE_KEY = 'private-key' + process.env.AGENT_WALLET_DIR = '/tmp/agent-wallet' + const { walletModule, resolveWalletProvider, provider } = loadWalletModule() + await walletModule.initWallet() + expect(resolveWalletProvider).toHaveBeenCalledWith({ network: 'tron' }) + expect(provider.getActiveWallet).toHaveBeenCalledTimes(1) + expect(process.env.AGENT_WALLET_PRIVATE_KEY).toBe('private-key') + expect(process.env.AGENT_WALLET_DIR).toBe('/tmp/agent-wallet') + await expect(walletModule.getWalletAddress()).resolves.toBe('TWalletAddress') + }) + it('builds tronWeb with the active wallet as default address', async () => { + process.env.AGENT_WALLET_PASSWORD = 'secret' + const { walletModule, tronWeb, createReadonlyTronWeb } = loadWalletModule() + await walletModule.initWallet() + const wallet = walletModule.getWallet() + const resolvedTronWeb = await wallet.getTronWeb('nile') + expect(createReadonlyTronWeb).toHaveBeenCalledWith('nile') + expect(resolvedTronWeb).toBe(tronWeb) + expect(tronWeb.address.toHex).toHaveBeenCalledWith('TWalletAddress') + expect(tronWeb.address.fromHex).toHaveBeenCalledWith('41abc') + expect(tronWeb.defaultAddress).toEqual({ + hex: '41abc', + base58: 'TWalletAddress', + }) + }) + it('signs, broadcasts, and normalizes typed-data signatures', async () => { + process.env.AGENT_WALLET_PASSWORD = 'secret' + const { walletModule, activeWallet, tronWeb } = loadWalletModule({ + activeWallet: { + getAddress: jest.fn().mockResolvedValue('TWalletAddress'), + signTransaction: jest.fn().mockResolvedValue('{"txID":"signed","raw_data":{"x":1}}'), + signMessage: jest.fn().mockResolvedValue('signed-message'), + signTypedData: jest.fn().mockResolvedValue('0xdeadbeef'), + }, + tronWeb: { + address: { + toHex: jest.fn().mockReturnValue('41abc'), + fromHex: jest.fn().mockReturnValue('TWalletAddress'), + }, + trx: { + sendRawTransaction: jest.fn().mockResolvedValue({ result: true, txid: 'tx-999' }), + }, + }, + }) + await walletModule.initWallet() + const wallet = walletModule.getWallet() + await expect( + wallet.signAndBroadcast({ transaction: { raw_data: { contract: [] } } }, 'mainnet'), + ).resolves.toEqual({ result: true, txid: 'tx-999' }) + expect(activeWallet.signTransaction).toHaveBeenCalledWith({ raw_data: { contract: [] } }) + expect(tronWeb.trx.sendRawTransaction).toHaveBeenCalledWith({ + txID: 'signed', + raw_data: { x: 1 }, + }) + await expect( + wallet.signTypedData( + 'Permit', + { name: 'Sun', chainId: 1, verifyingContract: 'TContract' }, + { Permit: [{ name: 'owner', type: 'address' }] }, + { owner: 'TWalletAddress' }, + ), + ).resolves.toBe('deadbeef') + expect(activeWallet.signTypedData).toHaveBeenCalledWith({ + domain: { name: 'Sun', chainId: 1, verifyingContract: 'TContract' }, + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + Permit: [{ name: 'owner', type: 'address' }], + }, + primaryType: 'Permit', + message: { owner: 'TWalletAddress' }, + }) + }) +}) +//# sourceMappingURL=wallet.test.js.map diff --git a/test/lib/wallet.test.ts b/test/lib/wallet.test.ts index 76dfd2c..5e2ca49 100644 --- a/test/lib/wallet.test.ts +++ b/test/lib/wallet.test.ts @@ -5,9 +5,6 @@ describe('wallet', () => { jest.resetModules() jest.clearAllMocks() process.env = { ...originalEnv } - delete process.env.TRON_PRIVATE_KEY - delete process.env.TRON_MNEMONIC - delete process.env.TRON_MNEMONIC_ACCOUNT_INDEX delete process.env.AGENT_WALLET_PASSWORD delete process.env.AGENT_WALLET_DIR delete process.env.AGENT_WALLET_PRIVATE_KEY @@ -24,6 +21,8 @@ describe('wallet', () => { function loadWalletModule(options?: { activeWallet?: Record tronWeb?: Record + getActiveWalletError?: Error + getActiveWalletValue?: Record | null }) { const activeWallet = options?.activeWallet ?? { getAddress: jest.fn().mockResolvedValue('TWalletAddress'), @@ -43,7 +42,15 @@ describe('wallet', () => { } const provider = { - getActiveWallet: jest.fn().mockResolvedValue(activeWallet), + getActiveWallet: options?.getActiveWalletError + ? jest.fn().mockRejectedValue(options.getActiveWalletError) + : jest + .fn() + .mockResolvedValue( + options?.getActiveWalletValue === undefined + ? activeWallet + : options.getActiveWalletValue, + ), } const resolveWalletProvider = jest.fn().mockReturnValue(provider) @@ -68,30 +75,34 @@ describe('wallet', () => { } } - it('leaves wallet unconfigured when no credentials are set', async () => { - const { walletModule, resolveWalletProvider } = loadWalletModule() + it('leaves wallet unconfigured when the wallet provider cannot resolve an active wallet', async () => { + const { walletModule, resolveWalletProvider, provider } = loadWalletModule({ + getActiveWalletError: new Error('No active wallet'), + }) await walletModule.initWallet() expect(walletModule.isWalletConfigured()).toBe(false) - expect(resolveWalletProvider).not.toHaveBeenCalled() + expect(resolveWalletProvider).toHaveBeenCalledWith({ network: 'tron' }) + expect(provider.getActiveWallet).toHaveBeenCalledTimes(1) expect(() => walletModule.getWallet()).toThrow('No wallet configured') }) - it('rejects multiple wallet configuration modes', async () => { - process.env.TRON_PRIVATE_KEY = 'pk' - process.env.AGENT_WALLET_PASSWORD = 'pw' + it('leaves wallet unconfigured when the wallet provider returns null', async () => { + const { walletModule, resolveWalletProvider, provider } = loadWalletModule({ + getActiveWalletValue: null, + }) - const { walletModule, resolveWalletProvider } = loadWalletModule() + await walletModule.initWallet() - await expect(walletModule.initWallet()).rejects.toThrow( - 'Set only one of TRON_PRIVATE_KEY, TRON_MNEMONIC, or AGENT_WALLET_PASSWORD.', - ) - expect(resolveWalletProvider).not.toHaveBeenCalled() + expect(walletModule.isWalletConfigured()).toBe(false) + expect(resolveWalletProvider).toHaveBeenCalledWith({ network: 'tron' }) + expect(provider.getActiveWallet).toHaveBeenCalledTimes(1) + expect(() => walletModule.getWallet()).toThrow('No wallet configured') }) - it('initializes agent-wallet from private key env and exposes address', async () => { - process.env.TRON_PRIVATE_KEY = 'private-key' + it('initializes agent-wallet and exposes address', async () => { + process.env.AGENT_WALLET_PRIVATE_KEY = 'private-key' process.env.AGENT_WALLET_DIR = '/tmp/agent-wallet' const { walletModule, resolveWalletProvider, provider } = loadWalletModule()