Skip to content

feat: update agent wallet#13

Merged
Will-Guan merged 6 commits intomainfrom
feat/update-agent-wallet
Mar 21, 2026
Merged

feat: update agent wallet#13
Will-Guan merged 6 commits intomainfrom
feat/update-agent-wallet

Conversation

@gummy789j
Copy link
Copy Markdown
Collaborator

No description provided.

@github-actions
Copy link
Copy Markdown

Code Review Report

Project: @bankofai/sun-cli
PR: mainfeat/update-agent-wallet
Review Date: 2026-03-21
Reviewer: AI Code Reviewer (Code Review Skill v1.0.0)


PR Overview

Branch Information

Property Value
From Branch main
To Branch feat/update-agent-wallet
Commits 4
Files Changed 5
Lines Added +23
Lines Removed -49

Commit History

Hash Message
ca8404e ops: update 1.0.2
f863cd7 Create audit-pr.yml
046677a fix: agent-wallet beta 7 update
c97ecd6 fix: version
713c7c7 feat: update agent wallet

Review Summary

Verdict

Verdict: ❌ Request Changes

Findings at a Glance

Critical Major Minor Suggestion
Count 1 2 2 2

Summary

This PR migrates sun-cli from legacy TRON_* environment variables to unified AGENT_WALLET_* variables, bumps @bankofai/agent-wallet from 2.2.12.3.0, and removes the bridge/shim logic that previously translated between the two naming conventions. The version is also updated from 1.0.11.0.2, and the CLI version string is now dynamically sourced from package.json rather than being hardcoded.

The intent is clean and the direction is correct: removing deprecated TRON_* fallbacks simplifies wallet.ts significantly (−26 lines). However, the migration is incomplete in a critical way: src/bin.ts was not updated to match. The preAction hook still writes CLI flag values (-k, -m, -i) into the old TRON_PRIVATE_KEY, TRON_MNEMONIC, and TRON_MNEMONIC_ACCOUNT_INDEX environment variables. The bridge code that previously forwarded those to AGENT_WALLET_* has been deleted, meaning the -k and -m CLI flags silently no longer configure the wallet at runtime. This is a Critical regression that must be fixed before merge.

Additionally, initWallet() no longer handles the "no wallet configured" case — it calls resolveWalletProvider() unconditionally, where previously it returned early with _wallet = null. This removes graceful degradation for commands that support optional wallet operation.


Change Summary

Group 1 — Agent Wallet v2.3.0 Migration (src/lib/wallet.ts)

File Change Type Description
src/lib/wallet.ts Modified Removes shim/bridge env-var logic; delegates fully to resolveWalletProvider()

Purpose: agent-wallet@2.3.0 now handles env-var resolution internally. The old code in initWallet() manually read TRON_* and AGENT_WALLET_* env vars, picked one, and re-wrote them into AGENT_WALLET_* before calling resolveWalletProvider. That layer is now removed in favour of the library doing it natively. The type import also changes from BaseWalletWallet as BaseWallet to match the new export name in 2.3.0.


Group 2 — CLI Version Sync (src/bin.ts, package.json, package-lock.json)

File Change Type Description
src/bin.ts Modified Version string sourced dynamically from package.json instead of hardcoded
package.json Modified Version bumped 1.0.11.0.2; agent-wallet dep bumped ^2.2.1^2.3.0
package-lock.json Modified Lockfile updated to reflect new package versions

Purpose: Avoids version drift between package.json and the string displayed by sun --version. Keeps package metadata consistent.


Group 3 — Documentation Cleanup (README.md)

File Change Type Description
README.md Modified Removes TRON_PRIVATE_KEY / TRON_MNEMONIC / TRON_MNEMONIC_ACCOUNT_INDEX from all examples, tables, and security notes

Purpose: Aligns user-facing docs with the env-var migration — only AGENT_WALLET_* names are referenced going forward.


Detailed Findings


Critical

[C-01] CLI Flags -k / -m / -i Silently Broken — Write to Removed Env Vars

Property Value
Severity Critical
Category Correctness / Security
File src/bin.ts : Lines 61–66 (preAction hook, unchanged in this PR)

Description

The preAction hook in bin.ts maps the -k/--private-key, -m/--mnemonic, and -i/--mnemonic-account-index CLI flags to environment variables. It writes to the old legacy names that were just deprecated:

if (rootOpts.privateKey)         process.env.TRON_PRIVATE_KEY = rootOpts.privateKey
if (rootOpts.mnemonic)           process.env.TRON_MNEMONIC = rootOpts.mnemonic
if (rootOpts.mnemonicAccountIndex) {
  process.env.TRON_MNEMONIC_ACCOUNT_INDEX = rootOpts.mnemonicAccountIndex
}

In main, the deleted bridge code in wallet.ts forwarded TRON_PRIVATE_KEYAGENT_WALLET_PRIVATE_KEY before calling resolveWalletProvider. That bridge no longer exists. resolveWalletProvider (agent-wallet 2.3.0) reads AGENT_WALLET_PRIVATE_KEY / AGENT_WALLET_MNEMONIC, not TRON_PRIVATE_KEY / TRON_MNEMONIC.

Impact: Any user or agent that passes -k <privateKey> or -m <mnemonic> on the command line will have no wallet loaded at runtime. Because initWallet() now calls resolveWalletProvider() unconditionally without a null-guard, this likely throws an error (or returns a null/no-op wallet), causing all write commands to fail silently or with a confusing error message. The raw private key is also still written to the process environment under the wrong name — it never reaches the wallet library, yet it exists in process memory.

Code

// src/bin.ts — preAction hook (unchanged in this PR, but now broken)
if (rootOpts.privateKey) process.env.TRON_PRIVATE_KEY = rootOpts.privateKey   // ← writes OLD var
if (rootOpts.mnemonic)   process.env.TRON_MNEMONIC = rootOpts.mnemonic        // ← writes OLD var
if (rootOpts.mnemonicAccountIndex) {
  process.env.TRON_MNEMONIC_ACCOUNT_INDEX = rootOpts.mnemonicAccountIndex     // ← writes OLD var
}

Recommendation

Update bin.ts to write to the new AGENT_WALLET_* env vars that resolveWalletProvider reads:

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.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX = rootOpts.mnemonicAccountIndex
}

Also remove the now-dead TRON_* assignments entirely to prevent key material leaking into unused env slots.


Major

[MJ-01] initWallet() Loses Graceful "No Wallet" Early-Exit — Breaks Optional-Wallet Commands

Property Value
Severity Major
Category Correctness
File src/lib/wallet.ts : Lines 14–17

Description

The old initWallet() checked configuredModes === 0 and returned early, leaving _wallet = null. This allowed commands that use isWalletConfigured() to detect a read-only mode and skip wallet-dependent operations gracefully.

The new initWallet() removes this guard entirely:

// NEW — always calls into resolveWalletProvider, no early exit
export async function initWallet(): Promise<void> {
  const provider = resolveWalletProvider({ network: 'tron' })
  const activeWallet = await provider.getActiveWallet()
  _wallet = new AgentWalletAdapter(activeWallet)
}

If no wallet env vars are set, resolveWalletProvider / getActiveWallet will either throw or return undefined. Wrapping undefined in new AgentWalletAdapter(undefined) will create a broken object that crashes on the first method call (getAddress, signTransaction, etc.), producing a confusing runtime error deep in the call stack rather than a clean "no wallet configured" message at startup.

Code

// src/lib/wallet.ts (before) — graceful early exit preserved
if (configuredModes === 0) {
  _wallet = null
  return
}

// src/lib/wallet.ts (after) — no guard, always proceeds
const provider = resolveWalletProvider({ network: 'tron' })
const activeWallet = await provider.getActiveWallet()
_wallet = new AgentWalletAdapter(activeWallet)

Recommendation

Check whether resolveWalletProvider / getActiveWallet can indicate "no wallet configured" without throwing, and handle it explicitly:

export async function initWallet(): Promise<void> {
  const provider = resolveWalletProvider({ network: 'tron' })
  const activeWallet = await provider.getActiveWallet()
  if (!activeWallet) {
    _wallet = null
    return
  }
  _wallet = new AgentWalletAdapter(activeWallet)
}

If getActiveWallet() always throws when no wallet is configured, wrap the entire block in a try/catch and set _wallet = null on the appropriate error type.


[MJ-02] No Null/Undefined Guard on getActiveWallet() Return Value

Property Value
Severity Major
Category Correctness
File src/lib/wallet.ts : Lines 15–17

Description

provider.getActiveWallet() is called and its result is immediately passed to new AgentWalletAdapter(activeWallet) without checking whether activeWallet is null or undefined. If the agent-wallet library returns a nullable type (common for "no active wallet" states), every method on the adapter (getAddress, signTransaction, etc.) will throw a TypeError: Cannot read properties of undefined — a cryptic error with no actionable guidance.

Code

const activeWallet = await provider.getActiveWallet()
_wallet = new AgentWalletAdapter(activeWallet)   // ← no null check before wrapping

Recommendation

const activeWallet = await provider.getActiveWallet()
if (activeWallet == null) {
  _wallet = null
  return
}
_wallet = new AgentWalletAdapter(activeWallet)

Minor

[MN-01] require() Mixed With ES Module import Statements in bin.ts

Property Value
Severity Minor
Category Code Quality
File src/bin.ts : Line 20

Description

The new version-reading code uses CommonJS require:

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

This is added to a file that otherwise uses only ES module import syntax. While it compiles and works because package.json sets "type": "commonjs", the mixing of require and import is inconsistent and will cause confusion if the project ever moves to ESM output, or if ts-node / a bundler is configured differently.

Recommendation

Use a proper ESM/TypeScript import instead. With "resolveJsonModule": true in tsconfig.json (verify it is enabled):

import { version } from '../package.json'

This is fully type-safe, consistent with the rest of the file, and does not require a manual type cast.


[MN-02] No User-Facing Migration Notice for TRON_*AGENT_WALLET_* Rename

Property Value
Severity Minor
Category Documentation
File README.md

Description

The README silently removes all references to TRON_PRIVATE_KEY and TRON_MNEMONIC, and the wallet.ts shim that silently accepted them is deleted. Existing users who have these variable names in .env files, CI pipelines, or deployment secrets will have their wallets stop working with no guidance. There is no changelog entry, migration section, or deprecation notice explaining what changed.

Recommendation

Add a brief migration note to the README (e.g., under a ## Migrating from v1.0.1 or ## Breaking Changes section):

## Breaking Changes in v1.0.2

The legacy `TRON_PRIVATE_KEY`, `TRON_MNEMONIC`, and `TRON_MNEMONIC_ACCOUNT_INDEX`
environment variables are no longer supported. Rename them to:

| Old | New |
|-----|-----|
| `TRON_PRIVATE_KEY` | `AGENT_WALLET_PRIVATE_KEY` |
| `TRON_MNEMONIC` | `AGENT_WALLET_MNEMONIC` |
| `TRON_MNEMONIC_ACCOUNT_INDEX` | `AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX` |

Suggestions

[S-01] initWallet() Should Reset _wallet at the Start of Each Call

File: src/lib/wallet.ts
Description: _wallet is a module-level singleton. If initWallet() is called more than once (e.g., during testing or re-initialization), the first call sets _wallet to a valid adapter and subsequent calls overwrite it — but on any intermediate error, _wallet retains its old value. Starting with _wallet = null at the top of initWallet() would make re-initialization safe and predictable.
Suggestion:

export async function initWallet(): Promise<void> {
  _wallet = null   // reset before attempting re-init
  const provider = resolveWalletProvider({ network: 'tron' })
  const activeWallet = await provider.getActiveWallet()
  if (activeWallet == null) return
  _wallet = new AgentWalletAdapter(activeWallet)
}

[S-02] Verify package-lock.json Integrity Hash Is Valid Before Merge

File: package-lock.json
Description: The @bankofai/agent-wallet integrity hash changed from sha512-397cAkV45... (v2.2.1) to sha512-Jezo0ffh... (v2.3.0). Since agent-wallet is a private/scoped package, it is worth confirming the new hash in the lockfile matches what is on the registry. If the npm install was run in a different environment or with a local tarball, the hash may not match what users will pull.
Suggestion: Run npm ci in a clean environment (e.g., CI) and confirm it succeeds without lockfile drift warnings before merging.


Positive Observations

Area Observation
Simplification Removing the env-var bridge shim cuts wallet.ts from ~40 lines to ~14 lines for initWallet(), making it dramatically easier to read and maintain.
Version sync Sourcing the CLI version from package.json dynamically (require('../package.json')) eliminates the class of bug where package.json and sun --version drift out of sync.
Doc alignment README is thoroughly updated to match the env-var rename — the option tables, examples, and security notes are all consistent.
Import rename Changing type BaseWallet to type Wallet as BaseWallet correctly reflects the new export name from agent-wallet@2.3.0, and the local alias avoids a name collision with @bankofai/sun-kit's Wallet.
Type safety The require('../package.json') as { version: string } cast, while a minor style issue, is explicit and type-safe in a CommonJS TypeScript context.

Checklist Results

Category Items Checked Pass Fail N/A Notes
Correctness 8 5 3 0 CLI flags silently broken; no null guard on wallet; no unconfigured-wallet exit
Security 6 5 1 0 Private key still written to env var (wrong name)
Performance 7 7 0 0 No new performance concerns
Code Quality 10 8 2 0 require mixed with import; no re-init reset
Testing 7 0 0 7 No test changes in this PR; no new tests for new behavior
Documentation 6 4 2 0 No migration guide; README references updated
Compatibility 5 2 3 0 Breaking change for TRON_* users; CLI flags regressed; graceful degradation removed
Observability 4 4 0 0 Error messages updated correctly

Disclaimer

This is an automated code review. It supplements but does not replace human review. The reviewer analyzed only the diff between main and feat/update-agent-wallet. Runtime behavior, integration testing against agent-wallet@2.3.0, and deployment impact are not covered.


Report generated by Code Review Skill v1.0.0
Date: 2026-03-21

@github-actions
Copy link
Copy Markdown

Code Review Report

Project: @bankofai/sun-cli
PR: main -> feat/update-agent-wallet
Review Date: 2026-03-21
Reviewer: AI Code Reviewer (Code Review Skill v1.0.0)


PR Overview

Branch Information

Property Value
From Branch main
To Branch feat/update-agent-wallet
Commits 6
Files Changed 22
Lines Added +693
Lines Removed -686

Commit History

Hash Message
095ed1e fix: ai audit & unified lint
ca8404e ops: update 1.0.2
f863cd7 Create audit-pr.yml
046677a fix: agent-wallet beta 7 update
c97ecd6 fix: version
713c7c7 feat: update agent wallet

Review Summary

Verdict

Verdict: Request Changes

Findings at a Glance

Critical Major Minor Suggestion
Count 0 2 3 3

Summary

This PR upgrades @bankofai/agent-wallet from ^2.2.1 to ^2.3.0 and adapts the codebase to its updated API. The core change is in src/lib/wallet.ts, where the manual env-var merging + multi-mode conflict-detection logic is replaced by a simpler delegation to resolveWalletProvider. Documentation, tests, and CLI flag descriptions are updated throughout to drop the legacy TRON_* env var aliases.

The change is a reasonable simplification — the env-var bookkeeping in the old initWallet was redundant if the new library version handles that internally. However, the new implementation silently swallows all errors from the wallet provider, which is a meaningful regression in observability and debuggability. When a user supplies an invalid private key or a corrupted wallet file, the CLI will no longer report the underlying error; it will simply behave as if no wallet was configured. A second notable concern is the removal of the explicit multi-mode conflict guard with no documentation about how resolveWalletProvider resolves ambiguity.

The test suite is generally well-updated with good new coverage for the null-return and error-throw paths in initWallet. The compiled JS test artifacts are also kept in sync with the TypeScript sources.


Change Summary

1. Dependency & Version Bump

File Change Type Description
package.json Modified Version 1.0.11.0.2; agent-wallet dep ^2.2.1^2.3.0
package-lock.json Modified Lockfile updated to match new versions and hash

Purpose: Adopt the new @bankofai/agent-wallet v2.3.0 API throughout the project.


2. Core Wallet Initialization Refactor (src/lib/wallet.ts)

File Change Type Description
src/lib/wallet.ts Modified initWallet() rewritten; manual env merging + conflict detection removed; import type renamed

Purpose: Delegate all credential resolution to resolveWalletProvider in the new agent-wallet version, removing the local duplication of that logic.


3. CLI Entry-Point Env Var Rename (src/bin.ts)

File Change Type Description
src/bin.ts Modified -k/-m/-i flags now write AGENT_WALLET_* vars instead of TRON_*; version read from package.json

Purpose: Align CLI flag-to-env mappings with the canonical env var names used by @bankofai/agent-wallet.


4. Dead Code Removal

File Change Type Description
src/lib/command.ts Modified Unused BroadcastResult type removed
src/commands/liquidity.ts Modified Unused printKeyValue import removed

Purpose: Lint cleanup.


5. Documentation Update (README.md)

File Change Type Description
README.md Modified Removed all TRON_PRIVATE_KEY, TRON_MNEMONIC, TRON_MNEMONIC_ACCOUNT_INDEX references; flag table descriptions updated

Purpose: Documentation parity with the renamed env vars.


6. Test Suite Updates

File Change Type Description
test/lib/wallet.test.ts Modified Dropped TRON_* cleanup; added getActiveWalletError/getActiveWalletValue mock options; replaced old "no credentials" and "multi-mode reject" tests
test/bin.test.ts Modified Updated env var assertions to AGENT_WALLET_*
test/lib/output.test.ts Modified Updated error string fixture to AGENT_WALLET_PRIVATE_KEY
test/lib/wallet.test.js (+ other .js / .d.ts) Modified Compiled JS artifacts regenerated to match TS changes, also reformatted with single-quotes/no-semicolons

Purpose: Keep tests green after the wallet init refactor and env var renaming.


Detailed Findings


Major

[MJ-01] Silent Error Swallowing in initWallet()

Property Value
Severity Major
Category Correctness / Observability
File src/lib/wallet.ts : Lines 14–27

Description

The new initWallet() wraps the entire wallet-provider call in a bare catch block that discards the error and sets _wallet = null. This means any failure — invalid private key format, unreadable wallet file, missing passphrase, library bug — is silently swallowed. The caller only observes isWalletConfigured() === false, which is indistinguishable from "no credentials supplied at all."

When a user does supply credentials but has a typo in AGENT_WALLET_PRIVATE_KEY, the CLI will silently skip wallet setup and then throw 'No wallet configured' at the first write command — with no indication of what went wrong or why. This is a significant regression compared to the previous behaviour, which propagated errors directly.

Code

export async function initWallet(): Promise<void> {
  _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 {         // <-- error is silently discarded
    _wallet = null
  }
}

Recommendation

Re-throw errors that are not "no wallet configured" cases, or at minimum log/surface the error message so the user knows what failed. A targeted approach:

export async function initWallet(): Promise<void> {
  _wallet = null
  try {
    const provider = resolveWalletProvider({ network: 'tron' })
    const activeWallet = await provider.getActiveWallet()
    if (activeWallet === null || activeWallet === undefined) {
      return  // no credentials supplied — expected, stay unconfigured
    }
    _wallet = new AgentWalletAdapter(activeWallet)
  } catch (err) {
    // Re-throw so callers (and users) know what went wrong
    throw new Error(
      `Failed to initialise wallet: ${err instanceof Error ? err.message : String(err)}`,
    )
  }
}

If the design intent truly is "always be lenient", the error should at least be forwarded to console.error or the structured outputError helper so it is not invisible to operators.


[MJ-02] Removal of Multi-Mode Conflict Detection Without Documented Replacement

Property Value
Severity Major
Category Correctness / Documentation
File src/lib/wallet.ts : Lines 14–27 (diff context)

Description

The old initWallet() counted how many of {privateKey, mnemonic, walletPassword} were non-empty and threw a clear error when more than one was set:

'Set only one of TRON_PRIVATE_KEY, TRON_MNEMONIC, or AGENT_WALLET_PASSWORD.'

The new implementation removes this guard entirely and delegates conflict resolution to resolveWalletProvider. There is no documentation (in code, tests, or README) explaining which mode takes precedence when multiple AGENT_WALLET_* env vars are set simultaneously.

If resolveWalletProvider silently picks one source (e.g., private key wins over mnemonic), a user who accidentally sets both will have no warning that one of their settings is being ignored. If the library throws, the exception is swallowed by the new catch block (see MJ-01), making the user's misconfiguration completely invisible.

Recommendation

Either:

  1. Document explicitly (in README and in code comments) that resolveWalletProvider is the single source of truth and state what its precedence rules are, or
  2. Restore the conflict detection guard ahead of the resolveWalletProvider call so that the user gets an actionable error message.

Minor

[MN-01] Sensitive Data Written to process.env — Exposure in Process Listings

Property Value
Severity Minor
Category Security
File src/bin.ts : Lines 59–63

Description

The preAction hook copies CLI flag values (private key, mnemonic) into process.env. On Linux/macOS, environment variables of a running process are visible to any user that can read /proc/<pid>/environ (or via ps e). This was also true of the old TRON_* mapping, so the change does not introduce a new risk, but it persists an existing one.

Code

if (rootOpts.privateKey) process.env.AGENT_WALLET_PRIVATE_KEY = rootOpts.privateKey
if (rootOpts.mnemonic)   process.env.AGENT_WALLET_MNEMONIC = rootOpts.mnemonic

Recommendation

Consider passing credentials via a closure or scoped object rather than writing them into process.env. If the env-var route must remain (for compatibility with the library's own env reading), add a comment in the security section of the README noting this risk — the existing "prefer environment variables over command-line wallet flags" advice already partially covers it, but the risk should be acknowledged explicitly.


[MN-02] Duplicate delete Statements in Test beforeEach Cleanup

Property Value
Severity Minor
Category Code Quality
File test/lib/wallet.test.ts : Lines 8–13 (diff), test/lib/wallet.test.js : Lines 1387–1393

Description

Both the TypeScript source and the compiled JS test have duplicate delete statements for AGENT_WALLET_PASSWORD and AGENT_WALLET_DIR in the beforeEach block. This is harmless but indicates a copy-paste issue.

Code

delete process.env.AGENT_WALLET_PASSWORD   // line 8
delete process.env.AGENT_WALLET_DIR        // line 9
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   // duplicate — line 13
delete process.env.AGENT_WALLET_DIR        // duplicate — line 14

Recommendation

Remove the duplicated two delete lines.


[MN-03] require() with TypeScript Type Cast for package.json Version

Property Value
Severity Minor
Category Code Quality
File src/bin.ts : Line 21

Description

The dynamic version string is read using a CommonJS require() call with a TypeScript type assertion. While this works (the project uses "type": "commonjs"), it is inconsistent with the rest of the file, which uses ES-style import statements. It also bypasses TypeScript's resolveJsonModule path.

Code

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

Recommendation

Prefer an import declaration, which is type-safe and consistent with the module style used in the rest of the file:

import { version } from '../package.json'

(Ensure "resolveJsonModule": true is set in tsconfig.json, which is standard for this kind of project.)


Suggestions

[S-01] Add a Test for getActiveWallet() Returning undefined

File: test/lib/wallet.test.ts
Description: initWallet() explicitly checks for both null and undefined returns from provider.getActiveWallet(), but the test suite only covers the null case. The undefined path is exercised indirectly through the error-throw test but not explicitly. Adding a dedicated getActiveWalletValue: undefined test case would make the intent clearer and guard against future refactoring.


[S-02] Add JSDoc Comment to initWallet() Describing the Try/Catch Contract

File: src/lib/wallet.ts
Description: The new initWallet() has a different contract from the old one — it no longer throws. Callers and future contributors need to know that errors are deliberately absorbed. A short JSDoc explaining "errors from resolveWalletProvider are swallowed; check isWalletConfigured() after calling" would prevent unexpected re-introduction of throw-aware try/catch wrappers in callers.


[S-03] README — Mention the TRON_NETWORK Env Var Is Still Used

File: README.md
Description: The PR correctly removes TRON_PRIVATE_KEY / TRON_MNEMONIC references from the docs. However, TRON_NETWORK is still read by the CLI (process.env.TRON_NETWORK in bin.ts) and is listed in the global-flags table. This is consistent and correct; a clarifying note that TRON_NETWORK is a network-selector variable (not a wallet credential) and intentionally kept under the TRON_ prefix would prevent user confusion about why some TRON_* vars are gone but this one remains.


Positive Observations

Area Observation
Simplification Removing the manual env-var bookkeeping (copying AGENT_WALLET_* from TRON_* in initWallet) significantly reduces code surface and eliminates a potential source of drift between the two variable sets.
Dynamic Version Reading the CLI version from package.json at runtime (src/bin.ts line 21) ensures the --version flag is always in sync with the package, eliminating the old hardcoded '1.0.0' that was already out of date.
Test Coverage for Null/Error paths The new wallet.test.ts adds dedicated tests for null return and thrown error from getActiveWallet(). These paths were previously untested.
Dead Code Removal Removing BroadcastResult from command.ts and printKeyValue from liquidity.ts is clean housekeeping.
Consistent Lint Compiled JS test artifacts have been reformatted to single-quotes/no-semicolons matching the project's Prettier/ESLint config — this keeps the repo tidy and avoids noisy future diffs.
Backward-Compatible Docs The README security-considerations section was correctly updated to reference only the canonical AGENT_WALLET_* names, tightening the security guidance.

Checklist Results

Category Items Checked Pass Fail N/A Notes
Correctness 8 6 2 0 Silent error swallowing (MJ-01); missing conflict guard (MJ-02)
Security 10 9 1 0 CLI flag-to-env exposure of private key (MN-01)
Performance 7 7 0 0 No issues found
Code Quality 10 8 2 0 require() type cast (MN-03); duplicate deletes (MN-02)
Testing 7 6 1 0 Missing undefined return test (S-01)
Documentation 6 5 1 0 No docs on new try/catch contract or conflict resolution (S-02, MJ-02)
Compatibility 5 5 0 0 Breaking env var renames handled cleanly; version bump correct
Observability 4 3 1 0 Silent error swallowing (MJ-01) removes user-visible error messages

Disclaimer

This is an automated code review. It supplements but does not replace human review. The reviewer analyzed only the diff between the specified branches. Runtime behavior, integration testing, and deployment impact are not covered.


Report generated by Code Review Skill v1.0.0
Date: 2026-03-21

@github-actions
Copy link
Copy Markdown

Code Review Report

Project: @bankofai/sun-cli
PR: main -> feat/update-agent-wallet
Review Date: 2026-03-21
Reviewer: AI Code Reviewer (Code Review Skill v1.0.0)


PR Overview

Branch Information

Property Value
From Branch main
To Branch feat/update-agent-wallet
Commits 7
Files Changed 22
Lines Added +712
Lines Removed -711

Commit History

Hash Message
b70835d doc: update README
095ed1e fix: ai audit & unified lint
ca8404e ops: update 1.0.2
f863cd7 Create audit-pr.yml
046677a fix: agent-wallet beta 7 update
c97ecd6 fix: version
713c7c7 feat: update agent wallet

Review Summary

Verdict

Verdict: Request Changes

Findings at a Glance

Critical Major Minor Suggestion
Count 0 2 2 2

Summary

This PR upgrades @bankofai/agent-wallet from v2.2.1 to v2.3.0 and consolidates the wallet initialization path. The key architectural change is in src/lib/wallet.ts: the explicit multi-source environment variable resolution logic (which read TRON_PRIVATE_KEY, TRON_MNEMONIC, etc. and merged them into AGENT_WALLET_* vars) is replaced by a direct delegation to resolveWalletProvider() from the upgraded SDK. The PR also removes the old TRON_* legacy variable fallbacks and renames the type import from BaseWallet to Wallet as BaseWallet to match the updated SDK export surface. Supporting changes include: a dynamic version read in src/bin.ts, a CLI flag env-var remapping to AGENT_WALLET_*, a removed unused BroadcastResult type in src/lib/command.ts, a removed unused import in src/commands/liquidity.ts, updated documentation, and a full test-suite refresh to match the new behavior and style.

The overall direction of the change is sound — removing the legacy variable fallback layer reduces complexity and delegates responsibility to the SDK as intended. However, two issues warrant attention before merge. First, the new initWallet() swallows all errors silently, meaning misconfigured keystores, bad passwords, and internal SDK failures are all silently absorbed and later surface only as a generic "No wallet configured" message with no diagnostic context. Second, dropping the TRON_PRIVATE_KEY / TRON_MNEMONIC env variables is a breaking change for any existing user of the published 1.0.1 package who relied on those variables, and no runtime migration warning is emitted.


Change Summary

1. Core Wallet Initialization Refactor (src/lib/wallet.ts)

File Change Type Description
src/lib/wallet.ts Modified Rewrote initWallet() to delegate unconditionally to resolveWalletProvider() inside a try/catch. Removed the multi-source env var resolution and the multiple-modes guard. Updated type import alias for BaseWallet. Refactored getTronWeb to avoid a direct cast assignment on a separate line.

Purpose: Simplify wallet initialization by delegating all credential resolution logic to the agent-wallet SDK (v2.3.0), eliminating the hand-rolled variable merging layer.


2. CLI Entry-Point & Version Bump (src/bin.ts, package.json, package-lock.json)

File Change Type Description
src/bin.ts Modified Changed -k/-m/-i preAction env writes to target AGENT_WALLET_* vars. Version is now read dynamically from package.json via require().
package.json Modified Bumped version 1.0.11.0.2; bumped @bankofai/agent-wallet ^2.2.1^2.3.0.
package-lock.json Modified Lock-file updated to reflect the new agent-wallet 2.3.0 resolution.

Purpose: Ensure CLI flags write to the env vars that agent-wallet v2.3.0 actually reads, and keep the version string DRY.


3. Dead-Code Removal (src/lib/command.ts, src/commands/liquidity.ts)

File Change Type Description
src/lib/command.ts Modified Removed the unused local BroadcastResult type.
src/commands/liquidity.ts Modified Removed the unused printKeyValue import.

Purpose: Lint/quality clean-up.


4. Documentation Update (README.md)

File Change Type Description
README.md Modified Restructured "Wallet & Runtime Configuration" sections; added explicit deprecation notice for TRON_* vars; added security note about not storing secrets in MCP config files; updated flag reference table.

Purpose: Align documentation with the new wallet model and call out security guidance explicitly.


5. Test-Suite Refresh (all test/ files)

File Change Type Description
test/bin.test.ts / .js Modified Updated env var names in setup/assertions from TRON_*AGENT_WALLET_*.
test/lib/wallet.test.ts / .js Modified Replaced "no credentials" and "multiple modes" test cases with "provider throws" and "provider returns null" cases; added getActiveWalletError/getActiveWalletValue fixture options.
test/lib/output.test.ts / .js Modified Updated error-message fixture from TRON_PRIVATE_KEYAGENT_WALLET_PRIVATE_KEY.
All compiled .js / .d.ts Modified Reformatted from 4-space indented double-quoted CommonJS style to 2-space single-quoted style (unified lint).

Purpose: Align tests with the new wallet initialization behavior and apply a unified lint format.


Detailed Findings


Major

[MJ-01] Silent Error Swallowing in initWallet() Hides All Diagnostic Information

Property Value
Severity Major
Category Correctness / Observability
File src/lib/wallet.ts : Lines 14–27

Description

The new initWallet() wraps its entire body in a bare catch {} block with no error binding and no logging. Any error thrown by resolveWalletProvider() or provider.getActiveWallet() — including a corrupt keystore, an incorrect password, a missing wallet file, a network/IPC failure, or an internal SDK assertion — is silently discarded. The function returns normally and sets _wallet = null, causing isWalletConfigured() to return false.

From the user's perspective, a misconfigured keystore is indistinguishable from "no wallet provided at all". The only error they eventually see is the generic getWallet() exception:
"No wallet configured. Set AGENT_WALLET_PRIVATE_KEY, AGENT_WALLET_MNEMONIC, or AGENT_WALLET_PASSWORD for agent-wallet."

This message is actively misleading when the user has provided credentials but something went wrong during resolution. It also makes automated agent integrations harder to debug, since the root cause is irreversibly lost.

The old code avoided this by only calling resolveWalletProvider after confirming at least one credential was present, and propagating errors as thrown exceptions. The new approach has traded that explicit guard for implicit SDK delegation — but without at minimum logging the caught error.

Code

export async function initWallet(): Promise<void> {
  _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 {          // <-- bare catch, no error binding, no logging
    _wallet = null
  }
}

Recommendation

At minimum, log the caught error to stderr (behind a debug flag or unconditionally), so users and automated processes can distinguish "no credentials supplied" from "credentials supplied but initialization failed":

export async function initWallet(): Promise<void> {
  _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 (err) {
    // Emit to stderr so callers can distinguish misconfiguration from
    // "no wallet supplied". Do not throw — callers check isWalletConfigured().
    process.stderr.write(
      `[sun-cli] wallet init error: ${err instanceof Error ? err.message : String(err)}\n`,
    )
    _wallet = null
  }
}

Alternatively, if the intent is that initWallet() should never throw (to support read-only commands), consider re-throwing when an error is encountered and at least one AGENT_WALLET_* variable is set (i.e., the user clearly intended to configure a wallet but something went wrong).


[MJ-02] Breaking Change — TRON_PRIVATE_KEY / TRON_MNEMONIC Silently Ignored Without Warning

Property Value
Severity Major
Category Compatibility
File src/lib/wallet.ts (removed lines), src/bin.ts : Lines 59–63

Description

Prior to this PR, the wallet initializer accepted TRON_PRIVATE_KEY, TRON_MNEMONIC, and TRON_MNEMONIC_ACCOUNT_INDEX as aliases and internally remapped them to AGENT_WALLET_* before calling resolveWalletProvider(). This PR removes that remapping entirely.

Any user or deployment that has TRON_PRIVATE_KEY or TRON_MNEMONIC set in their environment or .env file will now silently receive an unconfigured wallet. There is no deprecation warning, no error, and no hint in the runtime output. This is especially problematic for automated/AI agent deployments where environment files are set centrally and may not be updated immediately when the package is upgraded from 1.0.1 to 1.0.2.

The README documents the removal, but documentation alone is not a safe migration strategy for a published npm package.

Code

// REMOVED from src/lib/wallet.ts (old code):
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() || ''

// REMOVED from src/bin.ts (old preAction):
if (rootOpts.privateKey) process.env.TRON_PRIVATE_KEY = rootOpts.privateKey
if (rootOpts.mnemonic) process.env.TRON_MNEMONIC = rootOpts.mnemonic

Recommendation

Add a runtime deprecation warning in initWallet() (or in the preAction hook) that fires when legacy TRON_* wallet variables are present but the new AGENT_WALLET_* equivalents are absent:

function warnLegacyEnvVars(): void {
  const legacyMappings: Array<[string, string]> = [
    ['TRON_PRIVATE_KEY', 'AGENT_WALLET_PRIVATE_KEY'],
    ['TRON_MNEMONIC', 'AGENT_WALLET_MNEMONIC'],
    ['TRON_MNEMONIC_ACCOUNT_INDEX', 'AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX'],
  ]
  for (const [legacy, replacement] of legacyMappings) {
    if (process.env[legacy] && !process.env[replacement]) {
      process.stderr.write(
        `[sun-cli] WARNING: ${legacy} is no longer supported. ` +
        `Use ${replacement} instead. See https://github.com/BofAI/sun-cli for migration.\n`,
      )
    }
  }
}

export async function initWallet(): Promise<void> {
  warnLegacyEnvVars()
  // ... rest of implementation
}

Minor

[MN-01] Sensitive Credentials Written to process.env via CLI Flags

Property Value
Severity Minor
Category Security
File src/bin.ts : Lines 59–63

Description

When users pass -k <private-key> or -m <mnemonic> via the CLI, the preAction hook writes those values into process.env.AGENT_WALLET_PRIVATE_KEY and process.env.AGENT_WALLET_MNEMONIC respectively. Writing plaintext private keys and mnemonics into process.env exposes them to any child process spawned by the CLI and to tools that inspect the process environment (e.g., /proc/<pid>/environ on Linux, ps -e on some systems, crash-dump tools).

This behavior predates the PR and was present using TRON_* vars; the PR perpetuates it under the new variable names. The README already warns about this ("Prefer environment variables over command-line wallet flags when possible, because shell history and process lists may expose secrets"), but the implementation continues the env-injection pattern.

Code

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.AGENT_WALLET_MNEMONIC_ACCOUNT_INDEX = rootOpts.mnemonicAccountIndex
}

Recommendation

Pass the credential values directly into resolveWalletProvider() (if the SDK supports it) rather than staging them in process.env. If the SDK requires env vars, consider clearing the env vars immediately after initWallet() completes:

// After initWallet() in the preAction hook or command handler:
delete process.env.AGENT_WALLET_PRIVATE_KEY
delete process.env.AGENT_WALLET_MNEMONIC

This is a pre-existing issue and not a regression introduced by this PR; it is noted here for awareness given the security-focused documentation additions in this same PR.


[MN-02] require('../package.json') Uses CommonJS require() with a Type Assertion in an ESM-style TypeScript File

Property Value
Severity Minor
Category Code Quality
File src/bin.ts : Line 21

Description

The version is now read with:

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

While this works in a CommonJS output target ("type": "commonjs" in package.json), mixing import statements (for ESM-style imports) with require() calls is inconsistent and can cause confusion when the build target changes. TypeScript also supports import ... assert { type: 'json' } (TS 4.5+) or import pkg from '../package.json' with resolveJsonModule: true, which are more idiomatic.

Additionally, the as { version: string } assertion provides no runtime guarantee; if package.json is missing the version field, this would silently produce undefined and program.version(undefined) would set the version to the string "undefined".

Recommendation

Use a typed JSON import instead if the TypeScript config permits it:

import pkg from '../package.json'
// ...
.version(pkg.version)

Or keep require() but add a runtime guard:

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

Suggestions

[S-01] Redundant Double-Assignment _wallet = null Inside the null/undefined Check

File: src/lib/wallet.ts : Lines 19–21
Description: Inside the try block, _wallet is already initialized to null at line 15, so the reassignment _wallet = null on line 20 (inside the if (activeWallet === null || activeWallet === undefined) branch) is a no-op. It adds visual noise without contributing correctness.
Suggestion: Remove the redundant assignment:

if (activeWallet === null || activeWallet === undefined) {
  return  // _wallet is already null from line 15
}

[S-02] Consider Emitting a Deprecation Warning for TRON_* Network Variables as Well

File: README.md, src/lib/wallet.ts
Description: The deprecation story focuses only on wallet variables (TRON_PRIVATE_KEY, TRON_MNEMONIC). The TRON_GRID_API_KEY fallback (an alias for TRONGRID_API_KEY) is still checked in the context module and its deprecation is not surfaced in the README.
Suggestion: Include TRON_GRID_API_KEY in the "deprecated" section of the README or add a runtime warning in src/lib/context.ts when TRON_GRID_API_KEY is detected alongside the non-deprecated TRONGRID_API_KEY, to maintain consistency with the deprecation strategy applied to wallet vars.


Positive Observations

Area Observation
Architecture Delegating credential resolution entirely to the SDK is the right long-term direction. The PR correctly identifies that the hand-rolled variable merging layer in initWallet() was a leaky abstraction.
Security Documentation The new README "CRITICAL SECURITY NOTE" block explicitly warns against storing private keys in MCP configuration files — a real-world risk for AI agent deployments that is worth calling out prominently.
Type Hygiene The import { type Wallet as BaseWallet } change correctly uses a type-only import, which eliminates a potential runtime footprint for a type that is only used for static checking.
Dead-Code Removal Removing the unused BroadcastResult type (src/lib/command.ts) and the unused printKeyValue import (src/commands/liquidity.ts) is good hygiene.
Test Coverage for New Behaviors The new getActiveWalletError and getActiveWalletValue: null fixture paths in wallet.test.ts directly exercise the two new silent-failure branches of initWallet(), which is exactly the right approach for testing error-handling code paths.
Dynamic Versioning Reading the CLI version from package.json at runtime eliminates the prior risk of the hardcoded '1.0.0' string drifting out of sync with the published package version.
Unified Lint Style The reformatting of all compiled test files from 4-space double-quoted style to 2-space single-quoted style improves consistency across the repository.

Checklist Results

Category Items Checked Pass Fail N/A Notes
Correctness 8 6 1 1 Error handling in initWallet() swallows all exceptions (MJ-01)
Security 10 8 1 1 CLI flags write secrets to process.env (MN-01, pre-existing)
Performance 7 7 0 0 No performance regressions identified
Code Quality 10 9 0 1 Minor: require() + type assertion for JSON (MN-02)
Testing 7 6 0 1 New branches are tested; no test for diagnostic stderr output
Documentation 6 6 0 0 README updated and security note added
Compatibility 5 3 1 1 TRON_* wallet vars removed without runtime migration warning (MJ-02)
Observability 4 2 1 1 No logging when wallet init silently fails (MJ-01)

Disclaimer

This is an automated code review. It supplements but does not replace human review. The reviewer analyzed only the diff between main and feat/update-agent-wallet. Runtime behavior, integration testing against agent-wallet v2.3.0, and deployment impact are not covered.


Report generated by Code Review Skill v1.0.0
Date: 2026-03-21

@Will-Guan Will-Guan merged commit a24edb4 into main Mar 21, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants