@sherwoodagent/cli 0.73.4 → 0.74.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/{abis-KP7M4IPM.js → abis-D7EDCKVZ.js} +2 -2
  2. package/dist/{addresses-DGB3D457.js → addresses-OFFTM6NG.js} +4 -4
  3. package/dist/{agent-UNSW5IPO.js → agent-IJOOONON.js} +8 -8
  4. package/dist/{chat-KT2WVDT2.js → chat-3PM3GP3C.js} +9 -10
  5. package/dist/{chat-KT2WVDT2.js.map → chat-3PM3GP3C.js.map} +1 -1
  6. package/dist/{chunk-ROKE6ZAW.js → chunk-2OHX3O55.js} +6 -20
  7. package/dist/chunk-2OHX3O55.js.map +1 -0
  8. package/dist/{chunk-GSC7PVEO.js → chunk-6MV4ESXM.js} +43 -7
  9. package/dist/chunk-6MV4ESXM.js.map +1 -0
  10. package/dist/chunk-7BMCLMSE.js +173 -0
  11. package/dist/chunk-7BMCLMSE.js.map +1 -0
  12. package/dist/{chunk-NPWYX6NU.js → chunk-BD4ZV7FQ.js} +3 -3
  13. package/dist/{chunk-BKJ7HYX7.js → chunk-DGLLSZ2D.js} +10 -10
  14. package/dist/chunk-DGLLSZ2D.js.map +1 -0
  15. package/dist/chunk-EGJESQXZ.js +1 -0
  16. package/dist/chunk-I2PC6TBZ.js +3887 -0
  17. package/dist/chunk-I2PC6TBZ.js.map +1 -0
  18. package/dist/{chunk-CHWBQJLT.js → chunk-JF7KAVOM.js} +8 -21
  19. package/dist/chunk-JF7KAVOM.js.map +1 -0
  20. package/dist/{chunk-DXJJMRBM.js → chunk-LHVSS27T.js} +2 -2
  21. package/dist/{chunk-2U4TWPWQ.js → chunk-MUINMYCE.js} +5 -5
  22. package/dist/{chunk-GU5VZGXB.js → chunk-N3NVFSDQ.js} +5 -5
  23. package/dist/{chunk-CZRJ5GWE.js → chunk-RAP6MUMB.js} +54 -24
  24. package/dist/chunk-RAP6MUMB.js.map +1 -0
  25. package/dist/{chunk-ZURDCYGU.js → chunk-RE3PPAXZ.js} +9 -5
  26. package/dist/chunk-RE3PPAXZ.js.map +1 -0
  27. package/dist/{chunk-IFL5SREW.js → chunk-UINMHN6S.js} +2 -2
  28. package/dist/chunk-WBQMGZ5X.js +1253 -0
  29. package/dist/chunk-WBQMGZ5X.js.map +1 -0
  30. package/dist/{client-NAL3HVLK.js → client-C3C6IXAH.js} +4 -4
  31. package/dist/{config-FAQO37S7.js → config-7HU4X7EK.js} +4 -4
  32. package/dist/{eas-QAH7XVLK.js → eas-G4TPLJ6S.js} +7 -7
  33. package/dist/{governor-S56M6BV6.js → governor-PYQQ7QRG.js} +7 -7
  34. package/dist/index.js +201 -1286
  35. package/dist/index.js.map +1 -1
  36. package/dist/{network-MKMX2NG6.js → network-WU2QC3L4.js} +3 -3
  37. package/dist/{price-HHDBMKIE.js → price-DGGB6W2G.js} +15 -37
  38. package/dist/price-DGGB6W2G.js.map +1 -0
  39. package/dist/providers-YOOQFBN2.js +31 -0
  40. package/dist/providers-YOOQFBN2.js.map +1 -0
  41. package/dist/{research-IJBOMYL3.js → research-KX3LCAOQ.js} +9 -9
  42. package/dist/{session-L67AVWBY.js → session-GUVSID3Z.js} +19 -174
  43. package/dist/session-GUVSID3Z.js.map +1 -0
  44. package/dist/{trade-LGFQEK3I.js → trade-WDPMFFYB.js} +277 -43
  45. package/dist/trade-WDPMFFYB.js.map +1 -0
  46. package/dist/{vault-XWFPGHRA.js → vault-WDRLJLJ6.js} +14 -9
  47. package/dist/{xmtp-6US7GH3Z.js → xmtp-Q4ZSQV2Q.js} +11 -15
  48. package/dist/xmtp-Q4ZSQV2Q.js.map +1 -0
  49. package/package.json +2 -1
  50. package/dist/chunk-BKJ7HYX7.js.map +0 -1
  51. package/dist/chunk-BQMOE4FJ.js +0 -1629
  52. package/dist/chunk-BQMOE4FJ.js.map +0 -1
  53. package/dist/chunk-CHWBQJLT.js.map +0 -1
  54. package/dist/chunk-CZRJ5GWE.js.map +0 -1
  55. package/dist/chunk-DIZEB2VV.js +0 -325
  56. package/dist/chunk-DIZEB2VV.js.map +0 -1
  57. package/dist/chunk-GSC7PVEO.js.map +0 -1
  58. package/dist/chunk-ROKE6ZAW.js.map +0 -1
  59. package/dist/chunk-ZURDCYGU.js.map +0 -1
  60. package/dist/price-HHDBMKIE.js.map +0 -1
  61. package/dist/research-4TBGYEVI.js +0 -14
  62. package/dist/session-L67AVWBY.js.map +0 -1
  63. package/dist/trade-LGFQEK3I.js.map +0 -1
  64. package/dist/xmtp-6US7GH3Z.js.map +0 -1
  65. /package/dist/{abis-KP7M4IPM.js.map → abis-D7EDCKVZ.js.map} +0 -0
  66. /package/dist/{addresses-DGB3D457.js.map → addresses-OFFTM6NG.js.map} +0 -0
  67. /package/dist/{agent-UNSW5IPO.js.map → agent-IJOOONON.js.map} +0 -0
  68. /package/dist/{chunk-NPWYX6NU.js.map → chunk-BD4ZV7FQ.js.map} +0 -0
  69. /package/dist/{client-NAL3HVLK.js.map → chunk-EGJESQXZ.js.map} +0 -0
  70. /package/dist/{chunk-DXJJMRBM.js.map → chunk-LHVSS27T.js.map} +0 -0
  71. /package/dist/{chunk-2U4TWPWQ.js.map → chunk-MUINMYCE.js.map} +0 -0
  72. /package/dist/{chunk-GU5VZGXB.js.map → chunk-N3NVFSDQ.js.map} +0 -0
  73. /package/dist/{chunk-IFL5SREW.js.map → chunk-UINMHN6S.js.map} +0 -0
  74. /package/dist/{config-FAQO37S7.js.map → client-C3C6IXAH.js.map} +0 -0
  75. /package/dist/{eas-QAH7XVLK.js.map → config-7HU4X7EK.js.map} +0 -0
  76. /package/dist/{governor-S56M6BV6.js.map → eas-G4TPLJ6S.js.map} +0 -0
  77. /package/dist/{network-MKMX2NG6.js.map → governor-PYQQ7QRG.js.map} +0 -0
  78. /package/dist/{research-4TBGYEVI.js.map → network-WU2QC3L4.js.map} +0 -0
  79. /package/dist/{research-IJBOMYL3.js.map → research-KX3LCAOQ.js.map} +0 -0
  80. /package/dist/{vault-XWFPGHRA.js.map → vault-WDRLJLJ6.js.map} +0 -0
@@ -1,37 +1,258 @@
1
1
  import {
2
2
  getResearchProvider
3
- } from "./chunk-BKJ7HYX7.js";
4
- import {
5
- UniswapProvider,
6
- getQuote
7
- } from "./chunk-DIZEB2VV.js";
3
+ } from "./chunk-DGLLSZ2D.js";
4
+ import "./chunk-EGJESQXZ.js";
8
5
  import {
9
6
  chatCompletion
10
- } from "./chunk-NPWYX6NU.js";
7
+ } from "./chunk-BD4ZV7FQ.js";
8
+ import {
9
+ getQuote
10
+ } from "./chunk-WBQMGZ5X.js";
11
11
  import {
12
12
  TOKENS
13
- } from "./chunk-IFL5SREW.js";
13
+ } from "./chunk-UINMHN6S.js";
14
14
  import {
15
15
  formatContractError,
16
16
  getAccount,
17
- getPublicClient
18
- } from "./chunk-ROKE6ZAW.js";
17
+ getPublicClient,
18
+ sendTxWithRetry,
19
+ waitForReceipt
20
+ } from "./chunk-2OHX3O55.js";
19
21
  import {
20
- getExplorerUrl
21
- } from "./chunk-DXJJMRBM.js";
22
+ getChain,
23
+ getExplorerUrl,
24
+ getNetwork
25
+ } from "./chunk-LHVSS27T.js";
22
26
  import {
27
+ getUniswapApiKey,
23
28
  loadConfig,
24
29
  saveConfig
25
- } from "./chunk-GSC7PVEO.js";
30
+ } from "./chunk-6MV4ESXM.js";
26
31
  import {
27
32
  ERC20_ABI
28
- } from "./chunk-BQMOE4FJ.js";
33
+ } from "./chunk-I2PC6TBZ.js";
29
34
 
30
35
  // src/commands/trade.ts
31
36
  import chalk from "chalk";
32
37
  import ora from "ora";
33
38
  import { confirm } from "@inquirer/prompts";
34
- import { isAddress, parseUnits as parseUnits2, formatUnits as formatUnits2 } from "viem";
39
+ import { isAddress as isAddress2, parseUnits as parseUnits2, formatUnits as formatUnits3 } from "viem";
40
+
41
+ // src/providers/uniswap.ts
42
+ import { isAddress } from "viem";
43
+ var API_BASE = "https://trade-api.gateway.uniswap.org/v1";
44
+ function getApiKey() {
45
+ const key = getUniswapApiKey();
46
+ if (!key) {
47
+ throw new Error(
48
+ "Uniswap API key not configured. Run 'sherwood config set --uniswap-api-key <key>' or set UNISWAP_API_KEY env var.\nGet your key at https://developers.uniswap.org/"
49
+ );
50
+ }
51
+ return key;
52
+ }
53
+ function apiHeaders() {
54
+ return {
55
+ "Content-Type": "application/json",
56
+ "x-api-key": getApiKey(),
57
+ "x-universal-router-version": "2.0"
58
+ };
59
+ }
60
+ function isUniswapXRouting(routing) {
61
+ return routing === "DUTCH_V2" || routing === "DUTCH_V3" || routing === "PRIORITY";
62
+ }
63
+ function getOutputAmount(q) {
64
+ if (isUniswapXRouting(q.routing)) {
65
+ const ux = q;
66
+ const firstOutput = ux.quote.orderInfo.outputs[0];
67
+ if (!firstOutput) throw new Error("UniswapX quote has no outputs");
68
+ return firstOutput.startAmount;
69
+ }
70
+ return q.quote.output.amount;
71
+ }
72
+ async function fetchWithRetry(url, init, maxRetries = 3) {
73
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
74
+ const response = await fetch(url, {
75
+ ...init,
76
+ signal: AbortSignal.timeout(3e4)
77
+ });
78
+ if (response.status !== 429 && response.status < 500) return response;
79
+ if (attempt === maxRetries) return response;
80
+ const delay = Math.min(200 * Math.pow(2, attempt) + Math.random() * 100, 1e4);
81
+ await new Promise((resolve) => setTimeout(resolve, delay));
82
+ }
83
+ throw new Error("Unreachable");
84
+ }
85
+ var UniswapProvider = class {
86
+ /**
87
+ * Get a quote from the Uniswap Trading API.
88
+ * Returns the optimal route (CLASSIC, PRIORITY, or UniswapX).
89
+ */
90
+ async quote(params) {
91
+ const account = getAccount();
92
+ const chainId = getChain().id;
93
+ const body = {
94
+ swapper: account.address,
95
+ tokenIn: params.tokenIn,
96
+ tokenOut: params.tokenOut,
97
+ tokenInChainId: String(chainId),
98
+ tokenOutChainId: String(chainId),
99
+ amount: params.amountIn.toString(),
100
+ type: "EXACT_INPUT",
101
+ slippageTolerance: 0.5,
102
+ routingPreference: "BEST_PRICE"
103
+ };
104
+ const res = await fetchWithRetry(`${API_BASE}/quote`, {
105
+ method: "POST",
106
+ headers: apiHeaders(),
107
+ body: JSON.stringify(body)
108
+ });
109
+ if (!res.ok) {
110
+ const err = await res.text();
111
+ throw new Error(`Uniswap quote failed (${res.status}): ${err}`);
112
+ }
113
+ const data = await res.json();
114
+ const amountOut = BigInt(getOutputAmount(data));
115
+ return {
116
+ amountOut,
117
+ priceImpact: 0,
118
+ route: `${data.routing}: ${params.tokenIn.slice(0, 8)}\u2192${params.tokenOut.slice(0, 8)}`
119
+ };
120
+ }
121
+ /**
122
+ * Get a full quote response (preserving the raw API response for swap execution).
123
+ */
124
+ async fullQuote(params) {
125
+ const account = getAccount();
126
+ const chainId = getChain().id;
127
+ const body = {
128
+ swapper: account.address,
129
+ tokenIn: params.tokenIn,
130
+ tokenOut: params.tokenOut,
131
+ tokenInChainId: String(chainId),
132
+ tokenOutChainId: String(chainId),
133
+ amount: params.amountIn.toString(),
134
+ type: "EXACT_INPUT",
135
+ slippageTolerance: params.slippageTolerance ?? 0.5,
136
+ routingPreference: "BEST_PRICE"
137
+ };
138
+ const res = await fetchWithRetry(`${API_BASE}/quote`, {
139
+ method: "POST",
140
+ headers: apiHeaders(),
141
+ body: JSON.stringify(body)
142
+ });
143
+ if (!res.ok) {
144
+ const err = await res.text();
145
+ throw new Error(`Uniswap quote failed (${res.status}): ${err}`);
146
+ }
147
+ const quoteResponse = await res.json();
148
+ const amountOut = BigInt(getOutputAmount(quoteResponse));
149
+ return { quoteResponse, amountOut, routing: quoteResponse.routing };
150
+ }
151
+ /**
152
+ * Check and handle token approval for Uniswap.
153
+ * Uses the Trading API's /check_approval endpoint.
154
+ */
155
+ async checkApproval(params) {
156
+ const account = getAccount();
157
+ const chainId = getChain().id;
158
+ const client = getPublicClient();
159
+ const res = await fetchWithRetry(`${API_BASE}/check_approval`, {
160
+ method: "POST",
161
+ headers: apiHeaders(),
162
+ body: JSON.stringify({
163
+ walletAddress: account.address,
164
+ token: params.token,
165
+ amount: params.amount.toString(),
166
+ chainId
167
+ })
168
+ });
169
+ if (!res.ok) {
170
+ const err = await res.text();
171
+ throw new Error(`Approval check failed (${res.status}): ${err}`);
172
+ }
173
+ const data = await res.json();
174
+ if (data.approval) {
175
+ const approvalHash = await sendTxWithRetry({
176
+ to: data.approval.to,
177
+ data: data.approval.data,
178
+ value: BigInt(data.approval.value || "0"),
179
+ account,
180
+ chain: getChain()
181
+ });
182
+ await waitForReceipt(approvalHash);
183
+ }
184
+ }
185
+ /**
186
+ * Execute a swap via the Uniswap Trading API.
187
+ *
188
+ * Full flow: check_approval → quote → swap → sign & broadcast.
189
+ */
190
+ async swap(params) {
191
+ const account = getAccount();
192
+ const client = getPublicClient();
193
+ const ETH_ADDRESS2 = "0x0000000000000000000000000000000000000000";
194
+ if (params.tokenIn !== ETH_ADDRESS2) {
195
+ await this.checkApproval({
196
+ token: params.tokenIn,
197
+ amount: params.amountIn
198
+ });
199
+ }
200
+ const { quoteResponse } = await this.fullQuote({
201
+ tokenIn: params.tokenIn,
202
+ tokenOut: params.tokenOut,
203
+ amountIn: params.amountIn,
204
+ slippageTolerance: params.slippageTolerance ?? 0.5
205
+ });
206
+ const quoteRaw = quoteResponse;
207
+ const { permitData, ...cleanQuote } = quoteRaw;
208
+ const swapRequest = { ...cleanQuote };
209
+ if (permitData && typeof permitData === "object") {
210
+ const typedData = permitData;
211
+ const primaryType = Object.keys(typedData.types).find((k) => k !== "EIP712Domain") ?? "PermitSingle";
212
+ const signature = await account.signTypedData({
213
+ domain: typedData.domain,
214
+ types: typedData.types,
215
+ primaryType,
216
+ message: typedData.values
217
+ });
218
+ swapRequest.signature = signature;
219
+ if (!isUniswapXRouting(quoteResponse.routing)) {
220
+ swapRequest.permitData = permitData;
221
+ }
222
+ }
223
+ const swapRes = await fetchWithRetry(`${API_BASE}/swap`, {
224
+ method: "POST",
225
+ headers: apiHeaders(),
226
+ body: JSON.stringify(swapRequest)
227
+ });
228
+ if (!swapRes.ok) {
229
+ const err = await swapRes.text();
230
+ throw new Error(`Uniswap swap failed (${swapRes.status}): ${err}`);
231
+ }
232
+ const swapData = await swapRes.json();
233
+ if (!swapData.swap?.data || swapData.swap.data === "" || swapData.swap.data === "0x") {
234
+ throw new Error("Empty swap data \u2014 quote may have expired. Try again.");
235
+ }
236
+ if (!isAddress(swapData.swap.to) || !isAddress(swapData.swap.from)) {
237
+ throw new Error("Invalid address in swap response");
238
+ }
239
+ const gasLimit = swapData.swap.gasLimit ? BigInt(swapData.swap.gasLimit) * 150n / 100n : void 0;
240
+ const hash = await sendTxWithRetry({
241
+ to: swapData.swap.to,
242
+ data: swapData.swap.data,
243
+ value: BigInt(swapData.swap.value || "0"),
244
+ gas: gasLimit,
245
+ account,
246
+ chain: getChain()
247
+ });
248
+ const receipt = await waitForReceipt(hash);
249
+ return {
250
+ hash,
251
+ success: receipt.status === "success",
252
+ gasUsed: receipt.gasUsed
253
+ };
254
+ }
255
+ };
35
256
 
36
257
  // src/lib/signals.ts
37
258
  var DEFAULT_CONFIG = {
@@ -278,7 +499,7 @@ function checkExit(entryPrice, currentPrice, highWaterPrice, config, signalResul
278
499
  }
279
500
 
280
501
  // src/lib/positions.ts
281
- import { formatUnits, parseUnits } from "viem";
502
+ import { formatUnits as formatUnits2, parseUnits } from "viem";
282
503
  function getOpenPositions() {
283
504
  const config = loadConfig();
284
505
  return config.positions ?? [];
@@ -328,13 +549,13 @@ async function getCurrentPrice(tokenAddress, tokenDecimals, feeTier) {
328
549
  amountIn: oneToken,
329
550
  fee: feeTier
330
551
  });
331
- return Number(formatUnits(amountOut, 6));
552
+ return Number(formatUnits2(amountOut, 6));
332
553
  }
333
554
 
334
555
  // src/commands/trade.ts
335
556
  var uniswap = new UniswapProvider();
336
557
  async function loadXmtp() {
337
- return import("./xmtp-6US7GH3Z.js");
558
+ return import("./xmtp-Q4ZSQV2Q.js");
338
559
  }
339
560
  var ETH_ADDRESS = "0x0000000000000000000000000000000000000000";
340
561
  var KNOWN_MEMECOINS = {
@@ -359,7 +580,7 @@ async function resolveToken(symbolOrAddress) {
359
580
  }
360
581
  let address;
361
582
  let symbol;
362
- if (isAddress(symbolOrAddress)) {
583
+ if (isAddress2(symbolOrAddress)) {
363
584
  address = symbolOrAddress;
364
585
  const client2 = getPublicClient();
365
586
  try {
@@ -431,8 +652,21 @@ function formatSignalValue(v) {
431
652
  const s = (v >= 0 ? "+" : "") + v.toFixed(2);
432
653
  return v > 0 ? chalk.green(s) : v < 0 ? chalk.red(s) : chalk.dim(s);
433
654
  }
655
+ var TRADING_API_NETWORKS = /* @__PURE__ */ new Set(["base", "base-sepolia"]);
434
656
  function registerTradeCommands(program) {
435
657
  const trade = program.command("trade").description("Memecoin trading \u2014 scan, buy, sell, monitor positions (Uniswap Trading API on Base)");
658
+ trade.hook("preAction", () => {
659
+ const network = getNetwork();
660
+ if (!TRADING_API_NETWORKS.has(network)) {
661
+ console.error(chalk.red(`trade commands are not supported on ${network}.`));
662
+ console.error(
663
+ chalk.dim(
664
+ "They require the Uniswap Trading API, which covers Base only. Sherwood currently deploys on Robinhood testnet (chain 46630)."
665
+ )
666
+ );
667
+ process.exit(1);
668
+ }
669
+ });
436
670
  trade.command("scan").description("Analyze token(s) using on-chain, social, and fundamental signals").option("--token <addr|symbol>", "Specific token to analyze (otherwise scans known memecoins)").option("--fund <name>", "Post results to fund chat").option("--yes", "Skip cost confirmation", false).action(async (opts) => {
437
671
  const targets = [];
438
672
  if (opts.token) {
@@ -512,22 +746,22 @@ function registerTradeCommands(program) {
512
746
  const ethBalance = await client.getBalance({ address: account.address });
513
747
  if (ethBalance < inputAmount) {
514
748
  console.error(chalk.red(
515
- `Insufficient ETH. Have ${formatUnits2(ethBalance, 18)}, need ${opts.amount}`
749
+ `Insufficient ETH. Have ${formatUnits3(ethBalance, 18)}, need ${opts.amount}`
516
750
  ));
517
751
  process.exit(1);
518
752
  }
519
753
  const wrapSpinner = ora("Wrapping ETH \u2192 WETH...").start();
520
754
  try {
521
- const { writeContractWithRetry, waitForReceipt: waitForReceiptFn } = await import("./client-NAL3HVLK.js");
755
+ const { writeContractWithRetry: writeContractWithRetry2, waitForReceipt: waitForReceiptFn } = await import("./client-C3C6IXAH.js");
522
756
  const wethAddr = TOKENS().WETH;
523
- const wrapHash = await writeContractWithRetry({
757
+ const wrapHash = await writeContractWithRetry2({
524
758
  address: wethAddr,
525
759
  abi: WETH_ABI,
526
760
  functionName: "deposit",
527
761
  args: [],
528
762
  value: inputAmount,
529
763
  account,
530
- chain: (await import("./network-MKMX2NG6.js")).getChain()
764
+ chain: (await import("./network-WU2QC3L4.js")).getChain()
531
765
  });
532
766
  await waitForReceiptFn(wrapHash);
533
767
  wrapSpinner.succeed(`Wrapped ${opts.amount} ETH \u2192 WETH`);
@@ -545,7 +779,7 @@ function registerTradeCommands(program) {
545
779
  });
546
780
  if (balance < inputAmount) {
547
781
  console.error(chalk.red(
548
- `Insufficient ${inputSymbol}. Have ${formatUnits2(balance, inputDecimals)}, need ${opts.amount}`
782
+ `Insufficient ${inputSymbol}. Have ${formatUnits3(balance, inputDecimals)}, need ${opts.amount}`
549
783
  ));
550
784
  process.exit(1);
551
785
  }
@@ -562,7 +796,7 @@ function registerTradeCommands(program) {
562
796
  expectedOut = result.amountOut;
563
797
  const routing = result.routing;
564
798
  quoteSpinner.succeed(
565
- `Quote: ${formatUnits2(result.amountOut, decimals)} ${symbol} (${routing} route)`
799
+ `Quote: ${formatUnits3(result.amountOut, decimals)} ${symbol} (${routing} route)`
566
800
  );
567
801
  } catch (err) {
568
802
  quoteSpinner.fail("Quote failed");
@@ -600,7 +834,7 @@ function registerTradeCommands(program) {
600
834
  args: [account.address]
601
835
  });
602
836
  const tokensReceived = tokenBalance > 0n ? tokenBalance : expectedOut;
603
- const entryPrice = Number(opts.amount) / Number(formatUnits2(tokensReceived, decimals));
837
+ const entryPrice = Number(opts.amount) / Number(formatUnits3(tokensReceived, decimals));
604
838
  const exitConfig = {
605
839
  stopLossPct: Number(opts.stopLoss) || DEFAULT_EXIT_CONFIG.stopLossPct,
606
840
  trailingStopPct: Number(opts.trailingStop) || DEFAULT_EXIT_CONFIG.trailingStopPct,
@@ -630,7 +864,7 @@ function registerTradeCommands(program) {
630
864
  console.log(chalk.dim("\u2500".repeat(40)));
631
865
  console.log(` Token: ${symbol} (${tokenAddr})`);
632
866
  console.log(` Spent: ${opts.amount} ${inputSymbol}`);
633
- console.log(` Received: ${formatUnits2(tokensReceived, decimals)} ${symbol}`);
867
+ console.log(` Received: ${formatUnits3(tokensReceived, decimals)} ${symbol}`);
634
868
  console.log(` Entry: ${entryPrice.toFixed(8)} ${inputSymbol}/${symbol}`);
635
869
  console.log(` Stop: -${exitConfig.stopLossPct}%`);
636
870
  if (exitConfig.trailingStopPct > 0) {
@@ -641,15 +875,15 @@ function registerTradeCommands(program) {
641
875
  }
642
876
  console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash))}`);
643
877
  try {
644
- const { createTradeAttestation, getEasScanUrl } = await import("./eas-QAH7XVLK.js");
645
- const { getChainContracts } = await import("./config-FAQO37S7.js");
646
- const { getChain: getActiveChain } = await import("./network-MKMX2NG6.js");
878
+ const { createTradeAttestation, getEasScanUrl } = await import("./eas-G4TPLJ6S.js");
879
+ const { getChainContracts } = await import("./config-7HU4X7EK.js");
880
+ const { getChain: getActiveChain } = await import("./network-WU2QC3L4.js");
647
881
  const vaultRecipient = getChainContracts(getActiveChain().id).vault;
648
882
  const { uid } = await createTradeAttestation(
649
883
  inputAddr,
650
884
  tokenAddr,
651
885
  inputAmount,
652
- formatUnits2(tokensReceived, decimals),
886
+ formatUnits3(tokensReceived, decimals),
653
887
  txHash,
654
888
  "BUY",
655
889
  vaultRecipient
@@ -664,7 +898,7 @@ function registerTradeCommands(program) {
664
898
  await postToChat(
665
899
  opts.fund,
666
900
  "TRADE_EXECUTED",
667
- `Bought ${formatUnits2(tokensReceived, decimals)} ${symbol} for ${opts.amount} ${inputSymbol} via Uniswap`,
901
+ `Bought ${formatUnits3(tokensReceived, decimals)} ${symbol} for ${opts.amount} ${inputSymbol} via Uniswap`,
668
902
  { token: symbol, address: tokenAddr, amountIn: opts.amount, inputToken: inputSymbol, txHash }
669
903
  );
670
904
  }
@@ -710,7 +944,7 @@ function registerTradeCommands(program) {
710
944
  expectedOut = result.amountOut;
711
945
  const routing = result.routing;
712
946
  quoteSpinner.succeed(
713
- `Quote: ${formatUnits2(result.amountOut, outputDecimals)} ${outputSymbol} (${routing} route)`
947
+ `Quote: ${formatUnits3(result.amountOut, outputDecimals)} ${outputSymbol} (${routing} route)`
714
948
  );
715
949
  } catch (err) {
716
950
  quoteSpinner.fail("Quote failed");
@@ -739,12 +973,12 @@ function registerTradeCommands(program) {
739
973
  console.error(chalk.red(formatContractError(err)));
740
974
  process.exit(1);
741
975
  }
742
- const outputReceived = Number(formatUnits2(expectedOut, outputDecimals));
976
+ const outputReceived = Number(formatUnits3(expectedOut, outputDecimals));
743
977
  const costBasis = pos ? Number(pos.amountIn) : 0;
744
978
  const inputMatchesOutput = pos ? (pos.inputTokenSymbol ?? "USDC").toUpperCase() === outputSymbol.toUpperCase() : outputSymbol.toUpperCase() === "USDC";
745
979
  const pnl = costBasis > 0 && inputMatchesOutput ? outputReceived - costBasis : 0;
746
980
  const pnlPct = costBasis > 0 && inputMatchesOutput ? pnl / costBasis * 100 : 0;
747
- const exitPrice = sellAmount > 0n ? outputReceived / Number(formatUnits2(sellAmount, decimals)) : 0;
981
+ const exitPrice = sellAmount > 0n ? outputReceived / Number(formatUnits3(sellAmount, decimals)) : 0;
748
982
  if (pos) {
749
983
  closePosition(tokenAddr, {
750
984
  exitPrice,
@@ -760,7 +994,7 @@ function registerTradeCommands(program) {
760
994
  console.log(chalk.bold("Position Closed"));
761
995
  console.log(chalk.dim("\u2500".repeat(40)));
762
996
  console.log(` Token: ${symbol}`);
763
- console.log(` Sold: ${formatUnits2(sellAmount, decimals)} ${symbol}`);
997
+ console.log(` Sold: ${formatUnits3(sellAmount, decimals)} ${symbol}`);
764
998
  console.log(` Received: ~${outputReceived.toFixed(outputDecimals <= 6 ? 2 : 6)} ${outputSymbol}`);
765
999
  if (costBasis > 0 && inputMatchesOutput) {
766
1000
  const posInputSymbol = pos?.inputTokenSymbol ?? "USDC";
@@ -769,15 +1003,15 @@ function registerTradeCommands(program) {
769
1003
  }
770
1004
  console.log(` Tx: ${chalk.dim(getExplorerUrl(txHash))}`);
771
1005
  try {
772
- const { createTradeAttestation, getEasScanUrl } = await import("./eas-QAH7XVLK.js");
773
- const { getChainContracts } = await import("./config-FAQO37S7.js");
774
- const { getChain: getActiveChain } = await import("./network-MKMX2NG6.js");
1006
+ const { createTradeAttestation, getEasScanUrl } = await import("./eas-G4TPLJ6S.js");
1007
+ const { getChainContracts } = await import("./config-7HU4X7EK.js");
1008
+ const { getChain: getActiveChain } = await import("./network-WU2QC3L4.js");
775
1009
  const vaultRecipient = getChainContracts(getActiveChain().id).vault;
776
1010
  const { uid } = await createTradeAttestation(
777
1011
  tokenAddr,
778
1012
  outputAddr,
779
1013
  sellAmount,
780
- formatUnits2(expectedOut, outputDecimals),
1014
+ formatUnits3(expectedOut, outputDecimals),
781
1015
  txHash,
782
1016
  "SELL",
783
1017
  vaultRecipient
@@ -792,7 +1026,7 @@ function registerTradeCommands(program) {
792
1026
  await postToChat(
793
1027
  opts.fund,
794
1028
  "TRADE_EXECUTED",
795
- `Sold ${formatUnits2(sellAmount, decimals)} ${symbol} for ~${outputReceived.toFixed(2)} ${outputSymbol}${inputMatchesOutput && costBasis > 0 ? ` (P&L: ${pnl >= 0 ? "+" : ""}${pnl.toFixed(2)})` : ""}`,
1029
+ `Sold ${formatUnits3(sellAmount, decimals)} ${symbol} for ~${outputReceived.toFixed(2)} ${outputSymbol}${inputMatchesOutput && costBasis > 0 ? ` (P&L: ${pnl >= 0 ? "+" : ""}${pnl.toFixed(2)})` : ""}`,
796
1030
  { token: symbol, address: tokenAddr, outputReceived, outputToken: outputSymbol, pnl, pnlPct, txHash }
797
1031
  );
798
1032
  }
@@ -812,7 +1046,7 @@ function registerTradeCommands(program) {
812
1046
  for (const pos of positions) {
813
1047
  try {
814
1048
  const current = await getCurrentPrice(pos.tokenAddress, pos.tokenDecimals, pos.feeTier);
815
- const qty = Number(formatUnits2(BigInt(pos.amountOut), pos.tokenDecimals));
1049
+ const qty = Number(formatUnits3(BigInt(pos.amountOut), pos.tokenDecimals));
816
1050
  const cost = Number(pos.amountIn);
817
1051
  const value = qty * current;
818
1052
  const pnl = value - cost;
@@ -900,7 +1134,7 @@ function registerTradeCommands(program) {
900
1134
  slippageTolerance: 1
901
1135
  // 1% for auto-sell
902
1136
  });
903
- const usdcReceived = Number(formatUnits2(sellQuote, 6));
1137
+ const usdcReceived = Number(formatUnits3(sellQuote, 6));
904
1138
  const costBasis = Number(pos.amountIn);
905
1139
  const pnlUsdc = usdcReceived - costBasis;
906
1140
  closePosition(pos.tokenAddress, {
@@ -946,4 +1180,4 @@ function sleep(ms) {
946
1180
  export {
947
1181
  registerTradeCommands
948
1182
  };
949
- //# sourceMappingURL=trade-LGFQEK3I.js.map
1183
+ //# sourceMappingURL=trade-WDPMFFYB.js.map