If your trading flow depends on uptime, precision, and repeatability, a web UI is useful but not enough.
I use CowSwap regularly, but the UI has had the following issues:
- frontend downtime (Annoying)
- a compromised domain incident that redirected to phishing content(Cow.fi Domain Hijack)
- lack of slippage price control (see Trader lost $50 million in March 2026)
- missing order types for my strategy (especially buy/sell ladders)
- no native way to define relative limit entries (for example, X% from market)
- occasional bad quotes on thin liquidity pairs
- UI crashing, I have fixed it with these PRs
So I built a TypeScript CLI on top of the CowSwap SDK to place orders with guardrails, even when the frontend is unavailable. The repository is here.
Try it yourself
git clone https://github.com/doncesarts/cowswap-cli
cd cowswap-cli
npm install
What I wanted
-
New type of orders
- Market sell / buy with explicit slippage.
- Sell/Buy ladders orders with relative price offsets around the current market price.
- Limit fixed-price limit orders.
-
Refresh local token registries from CowSwap and CoinGecko
- Specify address or symbol for tokens when the symbol is unavailable
- It downloads from trusted sources like CowSwap and CoinGecko the information of tokens, i.e., address - symbol so it can be used across the CLI commands.
- You can also add your custom registry file as a JSON if you only want to trust on your file.
-
Price quote protection
- Whenever executing an order it quotes the price on cowSwap and compares it with coingecko prices, if there is a significant discrepancy, it warns the user before executing the trade, and then its up to you to confirm it manually. So having at least another source of prices gives me more confidence in the accuracy of the trade.
-
Fallback path for order execution
- If the CowSwap frontend is unavailable, the CLI provides a reliable alternative to place orders directly through the SDK.
-
Automation-friendly
- The CLI is designed to be scriptable and easily integrated, in my case i created a
Makefileto ease common trading tasks, such as placing orders in different chains based on different "profiles" or wallets.
- The CLI is designed to be scriptable and easily integrated, in my case i created a
The architecture
A visual representation of how the CLI processes commands before interacting with the CoW Protocol.
CLI arguments
│
▼
Command parser
│
▼
Validation / token resolution
│
▼
Price + safety checks
│
▼
Order construction
│
▼
CoW SDK
│
├── quote / order API
│
└── wallet signing
│
▼
CoW Protocol
Example of the cli commands.
# Market buy with explicit slippage (Buy 0.5 WETH for USDC)
npm run buy-market -- --buy-token WETH --sell-token USDC --amount 0.5 --slippage 0.5
# Sell ladder with relative price offsets above market
npm run sell-ladder -- --sell-token WETH --buy-token USDC --amount 2 --percentages "1,3,5,8"
# Fixed-price limit sell (buy-price set the price on buy token value, sell-price set the price on sell token value)
# Example: Sell 1 WETH for USDC at a fixed buy price of 4200 USDC
npm run sell-limit -- --sell-token WETH --buy-token USDC --amount 1 --buy-price 4200
# Resolve token by address if symbol is unavailable
npm run token-info -- --token 0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 --network mainnet
# Refresh CowSwap + CoinGecko registries locally
npm run update-tokens-registry
That gives me a fallback path for order execution, plus a cleaner base for automation.
You can use it passing a private key or a ledger path (recommended).
Building the CLI
1) Commands are thin, typed, and strategy-focused
Each CLI command maps flags into a typed executor. The command surface is simple, and validation/execution complexity lives in shared utilities.
program
.command('sell-ladder')
.requiredOption('--sell-token <symbol>')
.requiredOption('--amount <amount>')
.requiredOption('--percentages <percentages>')
.option('--buy-token <symbol>', 'USDC')
.option('--ledger-path <path>')
.action(async (options) => executeSellLadderCommand(options));
Why this matters:
- Inputs look like trading intent, not protocol internals
- Flags stay consistent across order types
- Execution logic stays maintainable
2) Safety checks are in the execution path, not optional
Before placing orders, the shared command flow validates inputs, resolves token/network context, checks pricing, and asks for confirmation.
const confirmed = await checkPriceAndConfirm(
orderKind,
validated.buyToken,
validated.sellToken,
networkConfig.chainId,
amountPerOrder,
marketPrice,
);
if (!confirmed) {
process.exit(0);
}
Why this matters:
- Price sanity checks happen before submission
- You reduce accidental execution from stale or outlier quotes
- Confirmation is explicit when discrepancies on source prices occur.
- Even if private key is supported do not use it for production trading; prefer the ledger-based signing flow for security.
3) Sell ladders and market-relative logic are first-class
Sell ladder orders use percentage offsets above market (--percentages "1,3,5") and split the total amount across levels.
If you want a single market-relative limit order, a practical trick is using a one-level ladder.
Solving Real Gaps From the UI Path
- Frontend reliability risk: CLI gives an alternate execution interface.
- Missing strategy primitives: Sell ladders and relative offsets are available.
- Liquidity quote risk: Extra sanity checks before order submission.
- Token availability gaps: Symbol and address-based resolution supported.
- Security posture: Ledger-based signing flow supported.
Why Intermediate Developers Should Care
If you already use TypeScript and trade on-chain, this pattern gives you immediate leverage:
- reproducible execution
- scriptable strategy workflows
- less dependency on frontend state
- easier path from manual trading to automation
References
- For more technical details and usage examples, check out the repository: https://github.com/doncesarts/cowswap-cli
- CowSwap SDK docs: https://docs.cow.fi/cow-protocol/reference/sdks/cow-sdk
- CowSwap app: https://swap.cow.fi/
- Domain incident statement: https://x.com/CoWSwap/status/2044924940886163780
- Trade lost $50 million statement: https://x.com/CoWSwap/status/2032959076502581623
- UI fix PR context:
Top comments (0)