refactor: migrate CLI to NestJS architecture with test suite and UX improvements#13
Open
carlosfebres wants to merge 98 commits intomainfrom
Open
refactor: migrate CLI to NestJS architecture with test suite and UX improvements#13carlosfebres wants to merge 98 commits intomainfrom
carlosfebres wants to merge 98 commits intomainfrom
Conversation
- tronweb 6.0.4 → 6.2.0 (fixes axios DoS + validator vulns)
- @coral-xyz/anchor 0.31.1 → 0.32.1
- jest 30.1.3 → 30.2.0, ts-jest 29.4.1 → 29.4.6
- @typescript-eslint/{plugin,parser} 8.43.0 → 8.56.0
- eslint 9.35.0 → 10.0.0 (fixes minimatch ReDoS via transitive dep)
- viem range changed from ~2.40.1 to ^2.40.1
- pnpm.overrides: axios >=1.13.5, minimatch >=10.2.1
- pnpm.auditConfig.ignoreCves: bigint-buffer has no upstream fix (patched versions: <0.0.0)
Enable strictPropertyInitialization, noUnusedLocals, noUnusedParameters, noImplicitOverride; set skipLibCheck/skipDefaultLibCheck to false. Exclude src/scripts (has own node_modules) from main build. Fix four noUnusedLocals violations by prefixing unused params with _.
- Define QuoteRequestPayload interface in quote.ts (replaces request: any) - Type logger.table() with ConstructorParameters<typeof Table>[0] from cli-table3 - Replace Program/AnchorProvider/Transaction any aliases in svm-types.ts - Change SvmError.details and DecodedEvent.data from any to unknown - Define RawIntentPublishedData interface for safe event data transformation - Convert all catch (error: any) to catch (error: unknown) with type narrowing - Fix handleError(error: any) in SvmPublisher with object narrowing for Solana-specific fields - Change decodedData?: any to decodedData?: unknown in PublishResult - Remove unused PortalIdl import from svm-transaction.ts
- Replace jest.config.js with jest.config.ts (typed Config, coverageThreshold) - Add tests/ directory structure: blockchain/, config/, integration/, e2e/ - Add pass-through mocks for viem, tronweb, @solana/web3.js and stub for ora - Add test:unit and test:integration scripts to package.json - Exclude tests/ from root tsconfig.json to prevent dist/ contamination - Add allowJs:true and override exclude in tests/tsconfig.json - Use projectService:true in ESLint for multi-tsconfig project support pnpm test exits 0 (38/38 pass); pnpm build passes.
Add stricter rules: no-explicit-any (error), explicit-function-return-type (error, allowExpressions), no-floating-promises (error), require-await (error), no-console (error, allow warn/error), no-unsafe-assignment (warn). Fix all 46 resulting violations: add return type annotations to 10 functions, remove unnecessary async from 7 config functions, add eslint-disable to logger.ts (the legitimate console abstraction), update pre-commit to run pnpm typecheck, exclude src/scripts from ESLint (not in tsconfig).
…SK-022) - Add ValidationResult interface and abstract validate() to BasePublisher - Add protected handleError() and runSafely() to eliminate duplicate try-catch - Implement validate() on EvmPublisher, TvmPublisher, SvmPublisher - Add override keyword to publish/getBalance/validate on all publishers - Wrap all publish() implementations in runSafely() - Convert SvmPublisher private handleError to protected override
Create solana-client.ts (Connection + Anchor setup), pda-manager.ts (PDA derivations), transaction-builder.ts (replaces svm-transaction.ts). svm-publisher.ts now imports only 4 local modules. svm-client-factory.ts kept as barrel re-export for backward compat.
Bug 1 — TVM token loop: replace hardcoded reward.tokens[0] approval with
a loop over all reward.tokens, matching EVM behavior. Multi-token intents
on TVM previously silently skipped every token after the first.
Bug 2 — SVM proverAddress: add proverAddress as 7th param to
SvmPublisher.publish() matching the BasePublisher signature. Thread it
through PublishContext and use it as override in buildFundingTransaction.
Bug 3 — TVM key cleanup: wrap TVM publish body in try/finally so that
tronWeb.setPrivateKey('') always executes regardless of success or error.
Key material no longer persists on the TronWeb instance after publish.
Bug 4 — override keyword: already complete from TASK-022.
…or cases (TASK-030)
…lidation (TASK-031)
…URL selection (TASK-033)
…peline (TASK-036) Covers: full flow (quote → encode → publish), quote failure manual fallback, invalid address error propagation, insufficient balance validation, and publisher factory dispatch by chain type.
…ntent lifecycle, publisher pattern, chain registry, and quote service (TASK-040)
…nd review guide (TASK-041)
Add @param, @returns, and @example JSDoc to all exported types, interfaces, and functions across the seven priority files: commands/publish.ts, config/chains.ts, config/tokens.ts, config/env.ts, and all three publishers. Includes field-level docs on ChainConfig, TokenConfig, and EnvConfig — notably explaining why TokenConfig.addresses uses string keys (bigint cannot be a JS object key) and documenting each private-key format for EnvConfig.
Replace EnvSchema.parse with safeParse so Zod issues are caught and printed as human-readable lines before process.exit(1) fires. This ensures validation errors are visible instead of being swallowed by NestJS's disabled internal logger.
… types - Fix funder sent to quote API being the raw private key instead of the wallet address - Default recipient to the configured wallet on the destination chain - Add deriveAddress() helper supporting EVM (viem), TVM (TronWeb static), and SVM (base58/byte-array/JSON-array key formats) - Add ConfigService.getKeyForChainType() to select the correct key per chain - Fix rawKey selection always using EVM key regardless of source chain type - Filter token list to only show tokens deployed on the selected chain
When the zero address is used as a token, buildReward() sets nativeAmount = amount with tokens = [], and buildManualRoute() builds a native call with target = recipient, data = '0x', value = amount, matching solver PR #475 expectations. Also replaces the broken inputManualPortal fallback in publish.command.ts with a structured buildManualRoute() call that prompts for route amount.
Adds displayQuote() to DisplayService that renders a formatted table with source/destination token amounts, portal, prover, deadline, and estimated fulfillment time after a quote is successfully received.
Replace reference-first structure with progressive disclosure layout: hero tagline, terminal demo, 3-step quick start, intent explainer, chains/tokens tables, command reference, env config, and troubleshooting.
- Add @vercel/ncc to bundle the CLI into bundle/ at build time, resolving all @/ path aliases so the package works standalone - Update bin to ./bundle/index.js, files to ["bundle", ...] - Add #!/usr/bin/env node shebang to src/main.ts - Update start script and clean to cover bundle/ dir - Add bundle/ to .gitignore
The quote API can return a portalAddress different from the one in config. publish.command.ts correctly overrides portalAddress on the watchChain object, but publisher.getStatus was discarding it by re-looking up the chain from the registry using only the chain ID. Pass the full ChainConfig through so the EVM publisher uses chain.portalAddress directly, preserving any runtime portal override from the quote.
…ucceed/fail/warn Removes the DisplayService spinner started before publisher.publish() which ran concurrently with the publisher's own ora spinners, causing console.log output to merge onto the active spinner line. Adds explicit fallback branches to succeed(), fail(), and warn() so they always print even when no spinner is active, matching ora's visual style.
…nnet Replace the single cached PublicClient (always using chains.mainnet) with a per-chain Map keyed by chain.id. getPublicClient() now requires a Chain argument and caches by chain.id. publish(), getStatus(), getBalance(), and validate() all resolve the viem Chain from the source/destination chain ID and pass it through, so balance checks, token reads, waitForTransactionReceipt, and event queries hit the correct chain descriptor. Also removes two debug console.log statements from getStatus().
Remove hardcoded portal addresses from chain configs and require them to be supplied at publish time. Priority order: quote service → --portal-address / --prover-address CLI arg → interactive prompt. - Remove portalAddress from Base, Base Sepolia, Optimism Sepolia, Plasma Testnet, and Sepolia chain configs - Add --portal-address and --prover-address options to publish command - Add inputManualProver() prompt to PromptService (mirrors inputManualPortal) - Update getStatus signature in base/evm/tvm/svm publishers to accept optional portalAddress parameter - Remove unimplemented PORTAL_ADDRESS_* env var section from .env.example
Replace pnpm dev workflow with eco-routes-cli binary usage, add --private-key to the demo and Quick Start, and lead with npm i -g installation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A comprehensive refactor of the Routes CLI — migrating from a monolithic Commander-based structure to a modular, injectable NestJS application. The goal is improved maintainability, testability, and extensibility.
Key Changes
DisplayService,PromptService,QuoteService,RpcService,ChainsService,PublisherFactory, etc.)ConfigModulewith Zod-validated environment schema replaces scattered env reads and global state mutationKeyHandleabstraction for safe private key zeroization viauseAsync()--watch), quote summary table, friendly error messages, and help on bare invocationTest plan
pnpm install && pnpm buildcompletes without errorspnpm dev(no subcommand) shows help and exits 0pnpm testpasses all unit and integration tests