teleton 0.1.0 → 0.1.1

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.
@@ -7,9 +7,10 @@ import {
7
7
  ContextBuilder,
8
8
  MessageStore,
9
9
  UserStore,
10
+ fetchWithTimeout,
10
11
  getDatabase,
11
12
  initializeMemory
12
- } from "./chunk-WDUHRPGA.js";
13
+ } from "./chunk-MPU2XS5H.js";
13
14
  import {
14
15
  ALLOWED_EXTENSIONS,
15
16
  MAX_FILE_SIZES,
@@ -17,6 +18,30 @@ import {
17
18
  WORKSPACE_PATHS,
18
19
  WORKSPACE_ROOT
19
20
  } from "./chunk-7NJ46ZIX.js";
21
+ import {
22
+ COINGECKO_API_URL,
23
+ ELEVENLABS_TTS_URL,
24
+ GECKOTERMINAL_API_URL,
25
+ OPENAI_TTS_URL,
26
+ STONFI_API_BASE_URL,
27
+ TONAPI_BASE_URL
28
+ } from "./chunk-I6ZVPVLK.js";
29
+ import {
30
+ COMPACTION_KEEP_RECENT,
31
+ COMPACTION_MAX_MESSAGES,
32
+ COMPACTION_MAX_TOKENS_RATIO,
33
+ COMPACTION_SOFT_THRESHOLD_RATIO,
34
+ DEAL_VERIFICATION_WINDOW_SECONDS,
35
+ DEFAULT_GIFTS_QUERY_LIMIT,
36
+ MAX_POLL_QUESTION_LENGTH,
37
+ MAX_TOOL_RESULT_SIZE,
38
+ SECONDS_PER_DAY,
39
+ TELEGRAM_MAX_MESSAGE_LENGTH
40
+ } from "./chunk-5BEHAIBQ.js";
41
+ import {
42
+ MESSAGE_HANDLER_LOCK_TIMEOUT_MS,
43
+ TTS_TIMEOUT_MS
44
+ } from "./chunk-EBFMA7CL.js";
20
45
 
21
46
  // src/config/schema.ts
22
47
  import { z } from "zod";
@@ -50,7 +75,7 @@ var TelegramConfigSchema = z.object({
50
75
  group_policy: GroupPolicy.default("open"),
51
76
  group_allow_from: z.array(z.number()).default([]),
52
77
  require_mention: z.boolean().default(true),
53
- max_message_length: z.number().default(4096),
78
+ max_message_length: z.number().default(TELEGRAM_MAX_MESSAGE_LENGTH),
54
79
  typing_simulation: z.boolean().default(true),
55
80
  rate_limit_messages_per_second: z.number().default(1),
56
81
  rate_limit_groups_per_minute: z.number().default(20),
@@ -102,6 +127,7 @@ var DealsConfigSchema = z.object({
102
127
  expiry_check_interval_ms: z.number().default(6e4)
103
128
  }).default({});
104
129
  var MarketConfigSchema = z.object({
130
+ enabled: z.boolean().default(true),
105
131
  cache_ttl_minutes: z.number().default(15),
106
132
  refresh_interval_minutes: z.number().default(120)
107
133
  }).default({});
@@ -437,6 +463,7 @@ async function ensureWorkspace(config) {
437
463
  userPath: WORKSPACE_PATHS.USER,
438
464
  bootstrapPath: WORKSPACE_PATHS.BOOTSTRAP,
439
465
  strategyPath: WORKSPACE_PATHS.STRATEGY,
466
+ securityPath: WORKSPACE_PATHS.SECURITY,
440
467
  // Workspace directories
441
468
  memoryDir: WORKSPACE_PATHS.MEMORY_DIR,
442
469
  downloadsDir: WORKSPACE_PATHS.DOWNLOADS_DIR,
@@ -459,7 +486,8 @@ async function bootstrapTemplates(workspace) {
459
486
  { name: "MEMORY.md", path: workspace.memoryPath },
460
487
  { name: "IDENTITY.md", path: workspace.identityPath },
461
488
  { name: "USER.md", path: workspace.userPath },
462
- { name: "BOOTSTRAP.md", path: workspace.bootstrapPath }
489
+ { name: "BOOTSTRAP.md", path: workspace.bootstrapPath },
490
+ { name: "SECURITY.md", path: workspace.securityPath }
463
491
  ];
464
492
  for (const template of templates) {
465
493
  if (!existsSync3(template.path)) {
@@ -1563,10 +1591,10 @@ This session was compacted and migrated to a new session ID. The summary above p
1563
1591
  import { encodingForModel } from "js-tiktoken";
1564
1592
  var DEFAULT_COMPACTION_CONFIG = {
1565
1593
  enabled: true,
1566
- maxMessages: 200,
1594
+ maxMessages: COMPACTION_MAX_MESSAGES,
1567
1595
  maxTokens: 96e3,
1568
1596
  // Conservative: fits 128K context with buffer
1569
- keepRecentMessages: 20,
1597
+ keepRecentMessages: COMPACTION_KEEP_RECENT,
1570
1598
  memoryFlushEnabled: true,
1571
1599
  softThresholdTokens: 64e3
1572
1600
  // ~50% of 128K (smallest supported context)
@@ -1891,11 +1919,11 @@ var AgentRuntime = class {
1891
1919
  const ctx = model.contextWindow;
1892
1920
  this.compactionManager = new CompactionManager({
1893
1921
  enabled: true,
1894
- maxMessages: 200,
1895
- maxTokens: Math.floor(ctx * 0.75),
1896
- keepRecentMessages: 20,
1922
+ maxMessages: COMPACTION_MAX_MESSAGES,
1923
+ maxTokens: Math.floor(ctx * COMPACTION_MAX_TOKENS_RATIO),
1924
+ keepRecentMessages: COMPACTION_KEEP_RECENT,
1897
1925
  memoryFlushEnabled: true,
1898
- softThresholdTokens: Math.floor(ctx * 0.5)
1926
+ softThresholdTokens: Math.floor(ctx * COMPACTION_SOFT_THRESHOLD_RATIO)
1899
1927
  });
1900
1928
  } catch {
1901
1929
  this.compactionManager = new CompactionManager(DEFAULT_COMPACTION_CONFIG);
@@ -2133,7 +2161,6 @@ ${statsContext}`;
2133
2161
  input: block.arguments
2134
2162
  });
2135
2163
  let resultText = JSON.stringify(result, null, 2);
2136
- const MAX_TOOL_RESULT_SIZE = 5e4;
2137
2164
  if (resultText.length > MAX_TOOL_RESULT_SIZE) {
2138
2165
  console.warn(`\u26A0\uFE0F Tool result too large (${resultText.length} chars), truncating...`);
2139
2166
  const data = result.data;
@@ -2218,7 +2245,8 @@ ${statsContext}`;
2218
2245
  "telegram_send_video",
2219
2246
  "telegram_send_poll",
2220
2247
  "telegram_forward_message",
2221
- "telegram_reply_message"
2248
+ "telegram_reply_message",
2249
+ "deal_propose"
2222
2250
  ];
2223
2251
  const usedTelegramSendTool = totalToolCalls.some((tc) => telegramSendTools.includes(tc.name));
2224
2252
  if (!content && totalToolCalls.length > 0 && !usedTelegramSendTool) {
@@ -2319,9 +2347,9 @@ import { TelegramClient, Api } from "telegram";
2319
2347
  import { Logger, LogLevel } from "telegram/extensions/Logger.js";
2320
2348
  import { StringSession } from "telegram/sessions/index.js";
2321
2349
  import { NewMessage } from "telegram/events/index.js";
2322
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5 } from "fs";
2350
+ import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5, chmodSync } from "fs";
2323
2351
  import { dirname as dirname4 } from "path";
2324
- import input from "input";
2352
+ import { createInterface } from "readline";
2325
2353
 
2326
2354
  // src/telegram/formatting.ts
2327
2355
  function escapeHtml(text) {
@@ -2386,6 +2414,15 @@ function markdownToTelegramHtml(markdown) {
2386
2414
  }
2387
2415
 
2388
2416
  // src/telegram/client.ts
2417
+ function promptInput(question) {
2418
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
2419
+ return new Promise((resolve2) => {
2420
+ rl.question(question, (answer) => {
2421
+ rl.close();
2422
+ resolve2(answer);
2423
+ });
2424
+ });
2425
+ }
2389
2426
  var TelegramUserClient = class {
2390
2427
  client;
2391
2428
  config;
@@ -2432,6 +2469,7 @@ var TelegramUserClient = class {
2432
2469
  mkdirSync5(dir, { recursive: true });
2433
2470
  }
2434
2471
  writeFileSync3(this.config.sessionPath, sessionString, { encoding: "utf-8" });
2472
+ chmodSync(this.config.sessionPath, 384);
2435
2473
  console.log("\u2705 Session saved");
2436
2474
  } catch (error) {
2437
2475
  console.error("Failed to save session:", error);
@@ -2452,9 +2490,9 @@ var TelegramUserClient = class {
2452
2490
  } else {
2453
2491
  console.log("Starting authentication flow...");
2454
2492
  await this.client.start({
2455
- phoneNumber: async () => this.config.phone || await input.text("Phone number: "),
2456
- phoneCode: async () => await input.text("Verification code: "),
2457
- password: async () => await input.text("2FA password (if enabled): "),
2493
+ phoneNumber: async () => this.config.phone || await promptInput("Phone number: "),
2494
+ phoneCode: async () => await promptInput("Verification code: "),
2495
+ password: async () => await promptInput("2FA password (if enabled): "),
2458
2496
  onError: (err) => console.error("Auth error:", err)
2459
2497
  });
2460
2498
  console.log("\u2705 Authenticated");
@@ -3089,8 +3127,7 @@ var RateLimiter = class {
3089
3127
  };
3090
3128
  var ChatLock = class {
3091
3129
  locks = /* @__PURE__ */ new Map();
3092
- LOCK_TIMEOUT_MS = 12e4;
3093
- // 2 minutes
3130
+ LOCK_TIMEOUT_MS = MESSAGE_HANDLER_LOCK_TIMEOUT_MS;
3094
3131
  async acquire(chatId) {
3095
3132
  const existing = this.locks.get(chatId);
3096
3133
  if (existing) {
@@ -3320,7 +3357,8 @@ var MessageHandler = class {
3320
3357
  "telegram_send_video",
3321
3358
  "telegram_send_poll",
3322
3359
  "telegram_forward_message",
3323
- "telegram_reply_message"
3360
+ "telegram_reply_message",
3361
+ "deal_propose"
3324
3362
  ];
3325
3363
  const telegramSendCalled = hasToolCalls && response.toolCalls?.some((tc) => telegramSendTools.includes(tc.name));
3326
3364
  if (!telegramSendCalled && response.content && response.content.trim().length > 0) {
@@ -3690,7 +3728,7 @@ var MarketScraperService = class {
3690
3728
  this.isScrapingInProgress = true;
3691
3729
  console.log("\u{1F504} Starting full market scrape...");
3692
3730
  try {
3693
- const { runScraper } = await import("./scraper-DW5Z2AP5.js");
3731
+ const { runScraper } = await import("./scraper-PGYSNQRD.js");
3694
3732
  const result = await runScraper({
3695
3733
  workers: 4,
3696
3734
  limit: 0
@@ -3976,9 +4014,9 @@ var MarketPriceService = class {
3976
4014
  };
3977
4015
 
3978
4016
  // src/ton/wallet-service.ts
3979
- import { mnemonicNew, mnemonicToPrivateKey } from "@ton/crypto";
4017
+ import { mnemonicNew, mnemonicToPrivateKey, mnemonicValidate } from "@ton/crypto";
3980
4018
  import { WalletContractV5R1, TonClient, fromNano } from "@ton/ton";
3981
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync7, chmodSync } from "fs";
4019
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync7, chmodSync as chmodSync2 } from "fs";
3982
4020
  import { join as join9, dirname as dirname6 } from "path";
3983
4021
  import { getHttpEndpoint } from "@orbs-network/ton-access";
3984
4022
  var WALLET_FILE = join9(TELETON_ROOT, "wallet.json");
@@ -4004,7 +4042,7 @@ function saveWallet(wallet) {
4004
4042
  mkdirSync7(dir, { recursive: true });
4005
4043
  }
4006
4044
  writeFileSync5(WALLET_FILE, JSON.stringify(wallet, null, 2), "utf-8");
4007
- chmodSync(WALLET_FILE, 384);
4045
+ chmodSync2(WALLET_FILE, 384);
4008
4046
  }
4009
4047
  function loadWallet() {
4010
4048
  if (!existsSync9(WALLET_FILE)) {
@@ -4018,6 +4056,28 @@ function loadWallet() {
4018
4056
  return null;
4019
4057
  }
4020
4058
  }
4059
+ function walletExists() {
4060
+ return existsSync9(WALLET_FILE);
4061
+ }
4062
+ async function importWallet(mnemonic) {
4063
+ const valid = await mnemonicValidate(mnemonic);
4064
+ if (!valid) {
4065
+ throw new Error("Invalid mnemonic: words do not form a valid TON seed phrase");
4066
+ }
4067
+ const keyPair = await mnemonicToPrivateKey(mnemonic);
4068
+ const wallet = WalletContractV5R1.create({
4069
+ workchain: 0,
4070
+ publicKey: keyPair.publicKey
4071
+ });
4072
+ const address = wallet.address.toString({ bounceable: true, testOnly: false });
4073
+ return {
4074
+ version: "w5r1",
4075
+ address,
4076
+ publicKey: keyPair.publicKey.toString("hex"),
4077
+ mnemonic,
4078
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
4079
+ };
4080
+ }
4021
4081
  function getWalletAddress() {
4022
4082
  const wallet = loadWallet();
4023
4083
  return wallet?.address || null;
@@ -4041,8 +4101,8 @@ async function getWalletBalance(address) {
4041
4101
  }
4042
4102
  async function getTonPrice() {
4043
4103
  try {
4044
- const response = await fetch(
4045
- "https://api.coingecko.com/api/v3/simple/price?ids=the-open-network&vs_currencies=usd"
4104
+ const response = await fetchWithTimeout(
4105
+ `${COINGECKO_API_URL}/simple/price?ids=the-open-network&vs_currencies=usd`
4046
4106
  );
4047
4107
  if (!response.ok) {
4048
4108
  throw new Error(`CoinGecko API error: ${response.status}`);
@@ -4145,7 +4205,7 @@ var telegramSendMessageTool = {
4145
4205
  }),
4146
4206
  text: Type.String({
4147
4207
  description: "The message text to send (max 4096 characters)",
4148
- maxLength: 4096
4208
+ maxLength: TELEGRAM_MAX_MESSAGE_LENGTH
4149
4209
  }),
4150
4210
  replyToId: Type.Optional(
4151
4211
  Type.Number({
@@ -4192,7 +4252,7 @@ var telegramEditMessageTool = {
4192
4252
  }),
4193
4253
  text: Type2.String({
4194
4254
  description: "The new text content for the message (max 4096 characters)",
4195
- maxLength: 4096
4255
+ maxLength: TELEGRAM_MAX_MESSAGE_LENGTH
4196
4256
  })
4197
4257
  })
4198
4258
  };
@@ -4359,7 +4419,7 @@ var telegramScheduleMessageTool = {
4359
4419
  }),
4360
4420
  text: Type5.String({
4361
4421
  description: "The message text to send (max 4096 characters)",
4362
- maxLength: 4096
4422
+ maxLength: TELEGRAM_MAX_MESSAGE_LENGTH
4363
4423
  }),
4364
4424
  scheduleDate: Type5.String({
4365
4425
  description: "When to send the message (ISO 8601 format, e.g., '2024-12-25T10:00:00Z' or Unix timestamp as string)"
@@ -4615,7 +4675,7 @@ var telegramQuoteReplyTool = {
4615
4675
  }),
4616
4676
  text: Type8.String({
4617
4677
  description: "Your reply message text",
4618
- maxLength: 4096
4678
+ maxLength: TELEGRAM_MAX_MESSAGE_LENGTH
4619
4679
  }),
4620
4680
  quoteOffset: Type8.Optional(
4621
4681
  Type8.Number({
@@ -5086,7 +5146,7 @@ async function generateOpenAITTS(text, voice) {
5086
5146
  mkdirSync8(tempDir, { recursive: true });
5087
5147
  }
5088
5148
  const outputPath = join10(tempDir, `${randomUUID3()}.mp3`);
5089
- const response = await fetch("https://api.openai.com/v1/audio/speech", {
5149
+ const response = await fetchWithTimeout(OPENAI_TTS_URL, {
5090
5150
  method: "POST",
5091
5151
  headers: {
5092
5152
  Authorization: `Bearer ${apiKey}`,
@@ -5098,7 +5158,8 @@ async function generateOpenAITTS(text, voice) {
5098
5158
  voice,
5099
5159
  // alloy, echo, fable, onyx, nova, shimmer
5100
5160
  response_format: "mp3"
5101
- })
5161
+ }),
5162
+ timeoutMs: TTS_TIMEOUT_MS
5102
5163
  });
5103
5164
  if (!response.ok) {
5104
5165
  const error = await response.text();
@@ -5122,7 +5183,7 @@ async function generateElevenLabsTTS(text, voiceId) {
5122
5183
  mkdirSync8(tempDir, { recursive: true });
5123
5184
  }
5124
5185
  const outputPath = join10(tempDir, `${randomUUID3()}.mp3`);
5125
- const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
5186
+ const response = await fetchWithTimeout(`${ELEVENLABS_TTS_URL}/${voiceId}`, {
5126
5187
  method: "POST",
5127
5188
  headers: {
5128
5189
  "xi-api-key": apiKey,
@@ -5135,7 +5196,8 @@ async function generateElevenLabsTTS(text, voiceId) {
5135
5196
  stability: 0.5,
5136
5197
  similarity_boost: 0.75
5137
5198
  }
5138
- })
5199
+ }),
5200
+ timeoutMs: TTS_TIMEOUT_MS
5139
5201
  });
5140
5202
  if (!response.ok) {
5141
5203
  const error = await response.text();
@@ -6415,7 +6477,7 @@ FIELDS:
6415
6477
 
6416
6478
  NOTE: To change the photo, use a separate photo upload tool.
6417
6479
 
6418
- Example: Update your channel @zkproofagent with a new description.`,
6480
+ Example: Update your channel @my_channel with a new description.`,
6419
6481
  parameters: Type23.Object({
6420
6482
  channelId: Type23.String({
6421
6483
  description: "Channel or group ID to edit"
@@ -7178,8 +7240,8 @@ var telegramCreatePollTool = {
7178
7240
  description: "The chat ID where the poll will be created"
7179
7241
  }),
7180
7242
  question: Type30.String({
7181
- description: "The poll question/prompt (max 300 characters)",
7182
- maxLength: 300
7243
+ description: `The poll question/prompt (max ${MAX_POLL_QUESTION_LENGTH} characters)`,
7244
+ maxLength: MAX_POLL_QUESTION_LENGTH
7183
7245
  }),
7184
7246
  options: Type30.Array(
7185
7247
  Type30.String({
@@ -8453,7 +8515,7 @@ var telegramSendGiftExecutor = async (params, context) => {
8453
8515
  AND agent_gives_type = 'gift'
8454
8516
  AND agent_gives_gift_id = ?
8455
8517
  AND user_telegram_id = ?
8456
- AND user_payment_verified_at >= unixepoch() - 300
8518
+ AND user_payment_verified_at >= unixepoch() - ${DEAL_VERIFICATION_WINDOW_SECONDS}
8457
8519
  AND agent_sent_at IS NULL
8458
8520
  LIMIT 1`
8459
8521
  ).get(giftId, userId);
@@ -8543,7 +8605,7 @@ var telegramTransferCollectibleExecutor = async (params, context) => {
8543
8605
  AND agent_gives_type = 'gift'
8544
8606
  AND agent_gives_gift_id = ?
8545
8607
  AND user_telegram_id = ?
8546
- AND user_payment_verified_at >= unixepoch() - 300
8608
+ AND user_payment_verified_at >= unixepoch() - ${DEAL_VERIFICATION_WINDOW_SECONDS}
8547
8609
  AND agent_sent_at IS NULL
8548
8610
  LIMIT 1`
8549
8611
  ).get(msgId.toString(), toUserId);
@@ -9714,7 +9776,7 @@ var marketGetFloorExecutor = async (params, context) => {
9714
9776
  updatedAt: result.updatedAt,
9715
9777
  cacheAgeMinutes: cacheAgeMin,
9716
9778
  cacheStatus,
9717
- message: `${result.model} in ${result.collection}: ${result.floorTon.toLocaleString()} TON (${result.rarityPercent}% rarity, ${cacheAgeMin} min old)`
9779
+ message: `${result.model} in ${result.collection}: ${result.floorTon?.toLocaleString() ?? "N/A"} TON (${result.rarityPercent}% rarity, ${cacheAgeMin} min old)`
9718
9780
  }
9719
9781
  };
9720
9782
  } else {
@@ -9738,7 +9800,7 @@ var marketGetFloorExecutor = async (params, context) => {
9738
9800
  updatedAt: result.updatedAt,
9739
9801
  cacheAgeMinutes: cacheAgeMin,
9740
9802
  cacheStatus,
9741
- message: `${result.name} floor: ${result.floorTon.toLocaleString()} TON (~$${result.floorUsd?.toLocaleString() || "N/A"}, ${cacheAgeMin} min old)`
9803
+ message: `${result.name} floor: ${result.floorTon?.toLocaleString() ?? "N/A"} TON (~$${result.floorUsd?.toLocaleString() || "N/A"}, ${cacheAgeMin} min old)`
9742
9804
  }
9743
9805
  };
9744
9806
  }
@@ -10792,7 +10854,6 @@ var tonMyTransactionsExecutor = async (params, context) => {
10792
10854
 
10793
10855
  // src/agent/tools/dns/check.ts
10794
10856
  import { Type as Type73 } from "@sinclair/typebox";
10795
- var TONAPI_BASE = "https://tonapi.io/v2";
10796
10857
  var dnsCheckTool = {
10797
10858
  name: "dns_check",
10798
10859
  description: "Check if a .ton domain is available, in auction, or already owned. Returns status with relevant details (price estimates, current bids, owner info).",
@@ -10825,7 +10886,7 @@ var dnsCheckExecutor = async (params, context) => {
10825
10886
  };
10826
10887
  }
10827
10888
  const fullDomain = `${domain}.ton`;
10828
- const dnsInfoResponse = await fetch(`${TONAPI_BASE}/dns/${fullDomain}`, {
10889
+ const dnsInfoResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/${fullDomain}`, {
10829
10890
  headers: { Accept: "application/json" }
10830
10891
  });
10831
10892
  if (dnsInfoResponse.status === 404) {
@@ -10868,7 +10929,7 @@ var dnsCheckExecutor = async (params, context) => {
10868
10929
  }
10869
10930
  };
10870
10931
  }
10871
- const auctionsResponse = await fetch(`${TONAPI_BASE}/dns/auctions?tld=ton`, {
10932
+ const auctionsResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/auctions?tld=ton`, {
10872
10933
  headers: { Accept: "application/json" }
10873
10934
  });
10874
10935
  if (auctionsResponse.ok) {
@@ -10916,7 +10977,6 @@ var dnsCheckExecutor = async (params, context) => {
10916
10977
 
10917
10978
  // src/agent/tools/dns/auctions.ts
10918
10979
  import { Type as Type74 } from "@sinclair/typebox";
10919
- var TONAPI_BASE2 = "https://tonapi.io/v2";
10920
10980
  var dnsAuctionsTool = {
10921
10981
  name: "dns_auctions",
10922
10982
  description: "List all active .ton domain auctions. Returns domains currently in auction with current bid prices, number of bids, and end times.",
@@ -10933,7 +10993,7 @@ var dnsAuctionsTool = {
10933
10993
  var dnsAuctionsExecutor = async (params, context) => {
10934
10994
  try {
10935
10995
  const { limit = 20 } = params;
10936
- const response = await fetch(`${TONAPI_BASE2}/dns/auctions?tld=ton`, {
10996
+ const response = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/auctions?tld=ton`, {
10937
10997
  headers: { Accept: "application/json" }
10938
10998
  });
10939
10999
  if (!response.ok) {
@@ -10990,7 +11050,6 @@ ${summary}`
10990
11050
 
10991
11051
  // src/agent/tools/dns/resolve.ts
10992
11052
  import { Type as Type75 } from "@sinclair/typebox";
10993
- var TONAPI_BASE3 = "https://tonapi.io/v2";
10994
11053
  var dnsResolveTool = {
10995
11054
  name: "dns_resolve",
10996
11055
  description: "Resolve a .ton domain to its associated wallet address. Only works for domains that are already owned (not available or in auction).",
@@ -11005,7 +11064,7 @@ var dnsResolveExecutor = async (params, context) => {
11005
11064
  let { domain } = params;
11006
11065
  domain = domain.toLowerCase().replace(/\.ton$/, "");
11007
11066
  const fullDomain = `${domain}.ton`;
11008
- const response = await fetch(`${TONAPI_BASE3}/dns/${fullDomain}`, {
11067
+ const response = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/${fullDomain}`, {
11009
11068
  headers: { Accept: "application/json" }
11010
11069
  });
11011
11070
  if (response.status === 404) {
@@ -11146,7 +11205,6 @@ import { mnemonicToPrivateKey as mnemonicToPrivateKey4 } from "@ton/crypto";
11146
11205
  import { WalletContractV5R1 as WalletContractV5R14, TonClient as TonClient6, toNano as toNano3, internal as internal3 } from "@ton/ton";
11147
11206
  import { Address as Address5, SendMode as SendMode3 } from "@ton/core";
11148
11207
  import { getHttpEndpoint as getHttpEndpoint6 } from "@orbs-network/ton-access";
11149
- var TONAPI_BASE4 = "https://tonapi.io/v2";
11150
11208
  var dnsBidTool = {
11151
11209
  name: "dns_bid",
11152
11210
  description: "Place a bid on an existing .ton domain auction. Bid must be at least 5% higher than current bid. The domain must already be in auction (use dns_check first to verify status and get current bid).",
@@ -11165,7 +11223,7 @@ var dnsBidExecutor = async (params, context) => {
11165
11223
  let { domain, amount } = params;
11166
11224
  domain = domain.toLowerCase().replace(/\.ton$/, "");
11167
11225
  const fullDomain = `${domain}.ton`;
11168
- const dnsResponse = await fetch(`${TONAPI_BASE4}/dns/${fullDomain}`, {
11226
+ const dnsResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/${fullDomain}`, {
11169
11227
  headers: { Accept: "application/json" }
11170
11228
  });
11171
11229
  if (dnsResponse.status === 404) {
@@ -11194,7 +11252,7 @@ var dnsBidExecutor = async (params, context) => {
11194
11252
  error: `Could not determine NFT address for ${fullDomain}`
11195
11253
  };
11196
11254
  }
11197
- const auctionsResponse = await fetch(`${TONAPI_BASE4}/dns/auctions?tld=ton`, {
11255
+ const auctionsResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/auctions?tld=ton`, {
11198
11256
  headers: { Accept: "application/json" }
11199
11257
  });
11200
11258
  if (auctionsResponse.ok) {
@@ -11269,10 +11327,11 @@ import { mnemonicToPrivateKey as mnemonicToPrivateKey5 } from "@ton/crypto";
11269
11327
  import { WalletContractV5R1 as WalletContractV5R15, TonClient as TonClient7, toNano as toNano4, internal as internal4, beginCell as beginCell2 } from "@ton/ton";
11270
11328
  import { Address as Address6, SendMode as SendMode4 } from "@ton/core";
11271
11329
  import { getHttpEndpoint as getHttpEndpoint7 } from "@orbs-network/ton-access";
11272
- var TONAPI_BASE5 = "https://tonapi.io/v2";
11273
11330
  var DNS_CHANGE_RECORD_OP = 1320284409;
11274
11331
  var DNS_SMC_ADDRESS_PREFIX = 40915;
11275
- var WALLET_RECORD_KEY = BigInt("0xe8d44050873dba865aa7c170ab4cce64d90839a34dcfd6cf71d14e0205443b1b");
11332
+ var WALLET_RECORD_KEY = BigInt(
11333
+ "0xe8d44050873dba865aa7c170ab4cce64d90839a34dcfd6cf71d14e0205443b1b"
11334
+ );
11276
11335
  var dnsLinkTool = {
11277
11336
  name: "dns_link",
11278
11337
  description: "Link a wallet address to a .ton domain you own. This sets the wallet record so the domain resolves to the specified address. If no wallet_address is provided, links to your own wallet.",
@@ -11308,7 +11367,7 @@ var dnsLinkExecutor = async (params, context) => {
11308
11367
  error: `Invalid wallet address: ${targetAddress}`
11309
11368
  };
11310
11369
  }
11311
- const dnsResponse = await fetch(`${TONAPI_BASE5}/dns/${fullDomain}`, {
11370
+ const dnsResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/${fullDomain}`, {
11312
11371
  headers: { Accept: "application/json" }
11313
11372
  });
11314
11373
  if (dnsResponse.status === 404) {
@@ -11398,9 +11457,10 @@ import { mnemonicToPrivateKey as mnemonicToPrivateKey6 } from "@ton/crypto";
11398
11457
  import { WalletContractV5R1 as WalletContractV5R16, TonClient as TonClient8, toNano as toNano5, internal as internal5, beginCell as beginCell3 } from "@ton/ton";
11399
11458
  import { Address as Address7, SendMode as SendMode5 } from "@ton/core";
11400
11459
  import { getHttpEndpoint as getHttpEndpoint8 } from "@orbs-network/ton-access";
11401
- var TONAPI_BASE6 = "https://tonapi.io/v2";
11402
11460
  var DNS_CHANGE_RECORD_OP2 = 1320284409;
11403
- var WALLET_RECORD_KEY2 = BigInt("0xe8d44050873dba865aa7c170ab4cce64d90839a34dcfd6cf71d14e0205443b1b");
11461
+ var WALLET_RECORD_KEY2 = BigInt(
11462
+ "0xe8d44050873dba865aa7c170ab4cce64d90839a34dcfd6cf71d14e0205443b1b"
11463
+ );
11404
11464
  var dnsUnlinkTool = {
11405
11465
  name: "dns_unlink",
11406
11466
  description: "Remove the wallet link from a .ton domain you own. This deletes the wallet record so the domain no longer resolves to any address.",
@@ -11422,7 +11482,7 @@ var dnsUnlinkExecutor = async (params, context) => {
11422
11482
  error: "Wallet not initialized. Contact admin to generate wallet."
11423
11483
  };
11424
11484
  }
11425
- const dnsResponse = await fetch(`${TONAPI_BASE6}/dns/${fullDomain}`, {
11485
+ const dnsResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/dns/${fullDomain}`, {
11426
11486
  headers: { Accept: "application/json" }
11427
11487
  });
11428
11488
  if (dnsResponse.status === 404) {
@@ -11506,7 +11566,6 @@ var dnsUnlinkExecutor = async (params, context) => {
11506
11566
 
11507
11567
  // src/agent/tools/jetton/balances.ts
11508
11568
  import { Type as Type80 } from "@sinclair/typebox";
11509
- var TONAPI_BASE7 = "https://tonapi.io/v2";
11510
11569
  var jettonBalancesTool = {
11511
11570
  name: "jetton_balances",
11512
11571
  description: "Get all Jetton (token) balances owned by the agent. Returns a list of all tokens with their balances, names, symbols, and verification status. Useful to check what tokens you currently hold.",
@@ -11521,9 +11580,12 @@ var jettonBalancesExecutor = async (params, context) => {
11521
11580
  error: "Wallet not initialized. Contact admin to generate wallet."
11522
11581
  };
11523
11582
  }
11524
- const response = await fetch(`${TONAPI_BASE7}/accounts/${walletData.address}/jettons`, {
11525
- headers: { Accept: "application/json" }
11526
- });
11583
+ const response = await fetchWithTimeout(
11584
+ `${TONAPI_BASE_URL}/accounts/${walletData.address}/jettons`,
11585
+ {
11586
+ headers: { Accept: "application/json" }
11587
+ }
11588
+ );
11527
11589
  if (!response.ok) {
11528
11590
  return {
11529
11591
  success: false,
@@ -11748,7 +11810,6 @@ import { mnemonicToPrivateKey as mnemonicToPrivateKey8 } from "@ton/crypto";
11748
11810
  import { WalletContractV5R1 as WalletContractV5R18, TonClient as TonClient10, toNano as toNano7, internal as internal7 } from "@ton/ton";
11749
11811
  import { Address as Address8, SendMode as SendMode7, beginCell as beginCell4 } from "@ton/core";
11750
11812
  import { getHttpEndpoint as getHttpEndpoint10 } from "@orbs-network/ton-access";
11751
- var TONAPI_BASE8 = "https://tonapi.io/v2";
11752
11813
  var JETTON_TRANSFER_OP = 260734629;
11753
11814
  var jettonSendTool = {
11754
11815
  name: "jetton_send",
@@ -11789,9 +11850,12 @@ var jettonSendExecutor = async (params, context) => {
11789
11850
  error: `Invalid recipient address: ${to}`
11790
11851
  };
11791
11852
  }
11792
- const jettonsResponse = await fetch(`${TONAPI_BASE8}/accounts/${walletData.address}/jettons`, {
11793
- headers: { Accept: "application/json" }
11794
- });
11853
+ const jettonsResponse = await fetchWithTimeout(
11854
+ `${TONAPI_BASE_URL}/accounts/${walletData.address}/jettons`,
11855
+ {
11856
+ headers: { Accept: "application/json" }
11857
+ }
11858
+ );
11795
11859
  if (!jettonsResponse.ok) {
11796
11860
  return {
11797
11861
  success: false,
@@ -11872,7 +11936,6 @@ var jettonSendExecutor = async (params, context) => {
11872
11936
 
11873
11937
  // src/agent/tools/jetton/info.ts
11874
11938
  import { Type as Type83 } from "@sinclair/typebox";
11875
- var TONAPI_BASE9 = "https://tonapi.io/v2";
11876
11939
  var jettonInfoTool = {
11877
11940
  name: "jetton_info",
11878
11941
  description: "Get detailed information about a Jetton (token) by its master contract address. Returns name, symbol, decimals, total supply, holders count, and verification status. Useful to research a token before buying or sending.",
@@ -11885,7 +11948,7 @@ var jettonInfoTool = {
11885
11948
  var jettonInfoExecutor = async (params, context) => {
11886
11949
  try {
11887
11950
  const { jetton_address } = params;
11888
- const response = await fetch(`${TONAPI_BASE9}/jettons/${jetton_address}`, {
11951
+ const response = await fetchWithTimeout(`${TONAPI_BASE_URL}/jettons/${jetton_address}`, {
11889
11952
  headers: { Accept: "application/json" }
11890
11953
  });
11891
11954
  if (response.status === 404) {
@@ -11970,7 +12033,6 @@ function formatLargeNumber(num) {
11970
12033
 
11971
12034
  // src/agent/tools/jetton/price.ts
11972
12035
  import { Type as Type84 } from "@sinclair/typebox";
11973
- var TONAPI_BASE10 = "https://tonapi.io/v2";
11974
12036
  var jettonPriceTool = {
11975
12037
  name: "jetton_price",
11976
12038
  description: "Get the current price of a Jetton (token) in USD and TON, along with 24h, 7d, and 30d price changes. Useful to check token value before swapping or to monitor investments.",
@@ -11983,8 +12045,8 @@ var jettonPriceTool = {
11983
12045
  var jettonPriceExecutor = async (params, context) => {
11984
12046
  try {
11985
12047
  const { jetton_address } = params;
11986
- const response = await fetch(
11987
- `${TONAPI_BASE10}/rates?tokens=${encodeURIComponent(jetton_address)}&currencies=usd,ton`,
12048
+ const response = await fetchWithTimeout(
12049
+ `${TONAPI_BASE_URL}/rates?tokens=${encodeURIComponent(jetton_address)}&currencies=usd,ton`,
11988
12050
  {
11989
12051
  headers: { Accept: "application/json" }
11990
12052
  }
@@ -11998,7 +12060,7 @@ var jettonPriceExecutor = async (params, context) => {
11998
12060
  const data = await response.json();
11999
12061
  const rateData = data.rates?.[jetton_address];
12000
12062
  if (!rateData) {
12001
- const infoResponse = await fetch(`${TONAPI_BASE10}/jettons/${jetton_address}`, {
12063
+ const infoResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/jettons/${jetton_address}`, {
12002
12064
  headers: { Accept: "application/json" }
12003
12065
  });
12004
12066
  if (infoResponse.status === 404) {
@@ -12019,7 +12081,7 @@ var jettonPriceExecutor = async (params, context) => {
12019
12081
  let symbol = "TOKEN";
12020
12082
  let name = "Unknown Token";
12021
12083
  try {
12022
- const infoResponse = await fetch(`${TONAPI_BASE10}/jettons/${jetton_address}`, {
12084
+ const infoResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/jettons/${jetton_address}`, {
12023
12085
  headers: { Accept: "application/json" }
12024
12086
  });
12025
12087
  if (infoResponse.ok) {
@@ -12076,7 +12138,6 @@ var jettonPriceExecutor = async (params, context) => {
12076
12138
 
12077
12139
  // src/agent/tools/jetton/search.ts
12078
12140
  import { Type as Type85 } from "@sinclair/typebox";
12079
- var STONFI_API = "https://api.ston.fi/v1";
12080
12141
  var jettonSearchTool = {
12081
12142
  name: "jetton_search",
12082
12143
  description: "Search for Jettons (tokens) by name or symbol. Returns a list of matching tokens with their addresses, useful for finding a token's address before swapping or checking prices. Search is case-insensitive.",
@@ -12098,7 +12159,7 @@ var jettonSearchExecutor = async (params, context) => {
12098
12159
  try {
12099
12160
  const { query, limit = 10 } = params;
12100
12161
  const searchQuery = query.toLowerCase().trim();
12101
- const response = await fetch(`${STONFI_API}/assets`, {
12162
+ const response = await fetchWithTimeout(`${STONFI_API_BASE_URL}/assets`, {
12102
12163
  headers: { Accept: "application/json" }
12103
12164
  });
12104
12165
  if (!response.ok) {
@@ -12301,7 +12362,6 @@ var jettonQuoteExecutor = async (params, context) => {
12301
12362
 
12302
12363
  // src/agent/tools/jetton/holders.ts
12303
12364
  import { Type as Type87 } from "@sinclair/typebox";
12304
- var TONAPI_BASE11 = "https://tonapi.io/v2";
12305
12365
  var jettonHoldersTool = {
12306
12366
  name: "jetton_holders",
12307
12367
  description: "Get the top holders of a Jetton (token). Shows wallet addresses and their balances. Useful to analyze token distribution and identify whale wallets.",
@@ -12321,8 +12381,8 @@ var jettonHoldersTool = {
12321
12381
  var jettonHoldersExecutor = async (params, context) => {
12322
12382
  try {
12323
12383
  const { jetton_address, limit = 10 } = params;
12324
- const response = await fetch(
12325
- `${TONAPI_BASE11}/jettons/${jetton_address}/holders?limit=${Math.min(limit, 100)}`,
12384
+ const response = await fetchWithTimeout(
12385
+ `${TONAPI_BASE_URL}/jettons/${jetton_address}/holders?limit=${Math.min(limit, 100)}`,
12326
12386
  {
12327
12387
  headers: { Accept: "application/json" }
12328
12388
  }
@@ -12344,7 +12404,7 @@ var jettonHoldersExecutor = async (params, context) => {
12344
12404
  let decimals = 9;
12345
12405
  let symbol = "TOKEN";
12346
12406
  try {
12347
- const infoResponse = await fetch(`${TONAPI_BASE11}/jettons/${jetton_address}`, {
12407
+ const infoResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/jettons/${jetton_address}`, {
12348
12408
  headers: { Accept: "application/json" }
12349
12409
  });
12350
12410
  if (infoResponse.ok) {
@@ -12366,7 +12426,10 @@ var jettonHoldersExecutor = async (params, context) => {
12366
12426
  isWallet: h.owner?.is_wallet || false
12367
12427
  };
12368
12428
  });
12369
- const totalTop = holders.reduce((sum, h) => sum + parseFloat(h.balance.replace(/,/g, "")), 0);
12429
+ const totalTop = holders.reduce(
12430
+ (sum, h) => sum + parseFloat(h.balance.replace(/,/g, "")),
12431
+ 0
12432
+ );
12370
12433
  let message = `Top ${holders.length} holders of ${symbol}:
12371
12434
 
12372
12435
  `;
@@ -12398,8 +12461,6 @@ var jettonHoldersExecutor = async (params, context) => {
12398
12461
 
12399
12462
  // src/agent/tools/jetton/history.ts
12400
12463
  import { Type as Type88 } from "@sinclair/typebox";
12401
- var TONAPI_BASE12 = "https://tonapi.io/v2";
12402
- var GECKOTERMINAL_API = "https://api.geckoterminal.com/api/v2";
12403
12464
  var jettonHistoryTool = {
12404
12465
  name: "jetton_history",
12405
12466
  description: "Get price history and performance data for a Jetton. Shows price changes over 24h, 7d, 30d periods, along with volume and market data. Useful for analyzing token trends.",
@@ -12412,15 +12473,15 @@ var jettonHistoryTool = {
12412
12473
  var jettonHistoryExecutor = async (params, context) => {
12413
12474
  try {
12414
12475
  const { jetton_address } = params;
12415
- const ratesResponse = await fetch(
12416
- `${TONAPI_BASE12}/rates?tokens=${encodeURIComponent(jetton_address)}&currencies=usd,ton`,
12476
+ const ratesResponse = await fetchWithTimeout(
12477
+ `${TONAPI_BASE_URL}/rates?tokens=${encodeURIComponent(jetton_address)}&currencies=usd,ton`,
12417
12478
  { headers: { Accept: "application/json" } }
12418
12479
  );
12419
- const geckoResponse = await fetch(
12420
- `${GECKOTERMINAL_API}/networks/ton/tokens/${jetton_address}`,
12480
+ const geckoResponse = await fetchWithTimeout(
12481
+ `${GECKOTERMINAL_API_URL}/networks/ton/tokens/${jetton_address}`,
12421
12482
  { headers: { Accept: "application/json" } }
12422
12483
  );
12423
- const infoResponse = await fetch(`${TONAPI_BASE12}/jettons/${jetton_address}`, {
12484
+ const infoResponse = await fetchWithTimeout(`${TONAPI_BASE_URL}/jettons/${jetton_address}`, {
12424
12485
  headers: { Accept: "application/json" }
12425
12486
  });
12426
12487
  let symbol = "TOKEN";
@@ -12456,13 +12517,17 @@ var jettonHistoryExecutor = async (params, context) => {
12456
12517
  const attrs = geckoData.data?.attributes;
12457
12518
  if (attrs) {
12458
12519
  if (attrs.volume_usd?.h24) {
12459
- volume24h = parseFloat(attrs.volume_usd.h24).toLocaleString(void 0, { maximumFractionDigits: 0 });
12520
+ volume24h = parseFloat(attrs.volume_usd.h24).toLocaleString(void 0, {
12521
+ maximumFractionDigits: 0
12522
+ });
12460
12523
  }
12461
12524
  if (attrs.fdv_usd) {
12462
12525
  fdv = parseFloat(attrs.fdv_usd).toLocaleString(void 0, { maximumFractionDigits: 0 });
12463
12526
  }
12464
12527
  if (attrs.market_cap_usd) {
12465
- marketCap = parseFloat(attrs.market_cap_usd).toLocaleString(void 0, { maximumFractionDigits: 0 });
12528
+ marketCap = parseFloat(attrs.market_cap_usd).toLocaleString(void 0, {
12529
+ maximumFractionDigits: 0
12530
+ });
12466
12531
  }
12467
12532
  }
12468
12533
  }
@@ -12524,7 +12589,6 @@ var jettonHistoryExecutor = async (params, context) => {
12524
12589
 
12525
12590
  // src/agent/tools/jetton/trending.ts
12526
12591
  import { Type as Type89 } from "@sinclair/typebox";
12527
- var STONFI_API2 = "https://api.ston.fi/v1";
12528
12592
  var jettonTrendingTool = {
12529
12593
  name: "jetton_trending",
12530
12594
  description: "Get trending/popular Jettons on the TON blockchain. Shows tokens ranked by trading volume and liquidity. Useful for discovering popular tokens.",
@@ -12541,7 +12605,7 @@ var jettonTrendingTool = {
12541
12605
  var jettonTrendingExecutor = async (params, context) => {
12542
12606
  try {
12543
12607
  const { limit = 10 } = params;
12544
- const response = await fetch(`${STONFI_API2}/assets`, {
12608
+ const response = await fetchWithTimeout(`${STONFI_API_BASE_URL}/assets`, {
12545
12609
  headers: { Accept: "application/json" }
12546
12610
  });
12547
12611
  if (!response.ok) {
@@ -12598,7 +12662,6 @@ var jettonTrendingExecutor = async (params, context) => {
12598
12662
 
12599
12663
  // src/agent/tools/jetton/pools.ts
12600
12664
  import { Type as Type90 } from "@sinclair/typebox";
12601
- var STONFI_API3 = "https://api.ston.fi/v1";
12602
12665
  var jettonPoolsTool = {
12603
12666
  name: "jetton_pools",
12604
12667
  description: "Get liquidity pools for a Jetton or list top pools by volume. Shows pool addresses, liquidity, volume, APY, and trading pairs. Useful for finding where to trade a token or analyzing DeFi opportunities.",
@@ -12620,7 +12683,7 @@ var jettonPoolsTool = {
12620
12683
  var jettonPoolsExecutor = async (params, context) => {
12621
12684
  try {
12622
12685
  const { jetton_address, limit = 10 } = params;
12623
- const response = await fetch(`${STONFI_API3}/pools`, {
12686
+ const response = await fetchWithTimeout(`${STONFI_API_BASE_URL}/pools`, {
12624
12687
  headers: { Accept: "application/json" }
12625
12688
  });
12626
12689
  if (!response.ok) {
@@ -12639,10 +12702,12 @@ var jettonPoolsExecutor = async (params, context) => {
12639
12702
  return token0.includes(targetAddress) || token1.includes(targetAddress) || targetAddress.includes(token0) || targetAddress.includes(token1);
12640
12703
  });
12641
12704
  }
12642
- pools = pools.filter((p) => !p.deprecated).sort((a, b) => parseFloat(b.volume_24h_usd || "0") - parseFloat(a.volume_24h_usd || "0")).slice(0, limit);
12643
- let assetMap = {};
12705
+ pools = pools.filter((p) => !p.deprecated).sort(
12706
+ (a, b) => parseFloat(b.volume_24h_usd || "0") - parseFloat(a.volume_24h_usd || "0")
12707
+ ).slice(0, limit);
12708
+ const assetMap = {};
12644
12709
  try {
12645
- const assetsResponse = await fetch(`${STONFI_API3}/assets`);
12710
+ const assetsResponse = await fetchWithTimeout(`${STONFI_API_BASE_URL}/assets`);
12646
12711
  if (assetsResponse.ok) {
12647
12712
  const assetsData = await assetsResponse.json();
12648
12713
  for (const asset of assetsData.asset_list || []) {
@@ -13071,7 +13136,7 @@ var dedustPoolsTool = {
13071
13136
  var dedustPoolsExecutor = async (params, context) => {
13072
13137
  try {
13073
13138
  const { jetton_address, pool_type, limit = 20 } = params;
13074
- const response = await fetch(`${DEDUST_API_URL}/pools`);
13139
+ const response = await fetchWithTimeout(`${DEDUST_API_URL}/pools`);
13075
13140
  if (!response.ok) {
13076
13141
  throw new Error(`DeDust API error: ${response.status} ${response.statusText}`);
13077
13142
  }
@@ -13080,9 +13145,7 @@ var dedustPoolsExecutor = async (params, context) => {
13080
13145
  if (jetton_address) {
13081
13146
  const normalizedAddress = jetton_address.toLowerCase();
13082
13147
  filteredPools = filteredPools.filter(
13083
- (pool) => pool.assets.some(
13084
- (asset) => asset.address?.toLowerCase() === normalizedAddress
13085
- )
13148
+ (pool) => pool.assets.some((asset) => asset.address?.toLowerCase() === normalizedAddress)
13086
13149
  );
13087
13150
  }
13088
13151
  if (pool_type) {
@@ -13924,7 +13987,7 @@ var JournalStore = class {
13924
13987
  values.outcome = params.outcome;
13925
13988
  }
13926
13989
  if (params.days) {
13927
- const cutoff = Math.floor(Date.now() / 1e3) - params.days * 86400;
13990
+ const cutoff = Math.floor(Date.now() / 1e3) - params.days * SECONDS_PER_DAY;
13928
13991
  conditions.push("timestamp >= @cutoff");
13929
13992
  values.cutoff = cutoff;
13930
13993
  }
@@ -13961,7 +14024,7 @@ var JournalStore = class {
13961
14024
  values.type = params.type;
13962
14025
  }
13963
14026
  if (params.days) {
13964
- const cutoff = Math.floor(Date.now() / 1e3) - params.days * 86400;
14027
+ const cutoff = Math.floor(Date.now() / 1e3) - params.days * SECONDS_PER_DAY;
13965
14028
  conditions.push("timestamp >= @cutoff");
13966
14029
  values.cutoff = cutoff;
13967
14030
  }
@@ -15017,7 +15080,7 @@ Returns:
15017
15080
  Teleton Casino needs sufficient balance to cover potential payouts (up to 5x the bet).
15018
15081
 
15019
15082
  IMPORTANT: When a player wants to bet, tell them to send TON to Teleton Casino address with their username as memo.
15020
- Example: "Send 2 TON to EQxxx with memo: ser_victor"`,
15083
+ Example: "Send 2 TON to EQxxx with memo: john_doe"`,
15021
15084
  parameters: Type105.Object({})
15022
15085
  };
15023
15086
  var casinoBalanceExecutor = async (params, context) => {
@@ -15085,6 +15148,8 @@ var casinoBalanceExecutor = async (params, context) => {
15085
15148
 
15086
15149
  // src/agent/tools/casino/spin.ts
15087
15150
  import { Type as Type106 } from "@sinclair/typebox";
15151
+
15152
+ // src/casino/game-engine.ts
15088
15153
  import { Api as Api53 } from "telegram";
15089
15154
 
15090
15155
  // src/casino/payment-verifier.ts
@@ -15244,6 +15309,16 @@ function checkCooldown(db, userId) {
15244
15309
  }
15245
15310
  return { allowed: true };
15246
15311
  }
15312
+ function checkAndUpdateCooldown(db, userId) {
15313
+ const txn = db.transaction(() => {
15314
+ const check = checkCooldown(db, userId);
15315
+ if (check.allowed) {
15316
+ updateCooldown(db, userId);
15317
+ }
15318
+ return check;
15319
+ });
15320
+ return txn();
15321
+ }
15247
15322
  function updateCooldown(db, userId) {
15248
15323
  const now = Math.floor(Date.now() / 1e3);
15249
15324
  db.prepare(
@@ -15433,59 +15508,19 @@ function checkRateLimit(userId, action) {
15433
15508
  return { allowed: true };
15434
15509
  }
15435
15510
 
15436
- // src/agent/tools/casino/spin.ts
15437
- var casinoSpinTool = {
15438
- name: "casino_spin",
15439
- description: `Execute a Teleton Casino slot machine spin with full security checks.
15440
-
15441
- Slot payout table (40% house edge):
15442
- - \u{1F3B0} 64 (777) = JACKPOT (5x bet)
15443
- - \u{1F3B0} 60-63 = Big win (2.5x bet)
15444
- - \u{1F3B0} 55-59 = Medium win (1.8x bet)
15445
- - \u{1F3B0} 43-54 = Small win (1.2x bet)
15446
- - \u{1F3B0} 1-42 = No win
15447
-
15448
- Process:
15449
- 1. Validates bet amount (min 0.1 TON, max 5% of bankroll)
15450
- 2. Checks user cooldown (30 seconds between spins)
15451
- 3. Verifies TON payment with username as memo
15452
- 4. Auto-discovers player wallet from transaction
15453
- 5. Sends \u{1F3B0} slot machine animation
15454
- 6. Processes house edge (5%) to daily jackpot
15455
- 7. AUTO-PAYOUT if player wins
15456
-
15457
- Tell the user: "Send X TON to [casino_address] with memo: your_username"`,
15458
- parameters: Type106.Object({
15459
- chat_id: Type106.String({
15460
- description: "Telegram chat ID where to send the spin"
15461
- }),
15462
- bet_amount: Type106.Number({
15463
- description: "Bet amount in TON",
15464
- minimum: 0.1
15465
- }),
15466
- player_username: Type106.String({
15467
- description: "Player's Telegram username (without @)"
15468
- }),
15469
- reply_to: Type106.Optional(
15470
- Type106.Number({
15471
- description: "Message ID to reply to"
15472
- })
15473
- )
15474
- })
15475
- };
15476
- var casinoSpinExecutor = async (params, context) => {
15511
+ // src/casino/game-engine.ts
15512
+ async function executeGame(config, params, context) {
15477
15513
  try {
15478
15514
  const { chat_id, bet_amount, player_username, reply_to } = params;
15479
- const oddsId = context.senderId.toString();
15515
+ const userId = context.senderId.toString();
15480
15516
  const username = player_username?.replace(/^@/, "").toLowerCase().trim();
15481
- const userId = oddsId;
15482
15517
  if (!username || username.length === 0) {
15483
15518
  return {
15484
15519
  success: false,
15485
15520
  error: "\u274C You need a Telegram @username to play at Teleton Casino. Set up your username in Telegram settings and try again!"
15486
15521
  };
15487
15522
  }
15488
- const rateCheck = checkRateLimit(oddsId, "casino_spin");
15523
+ const rateCheck = checkRateLimit(userId, config.toolName);
15489
15524
  if (!rateCheck.allowed) {
15490
15525
  return {
15491
15526
  success: false,
@@ -15494,20 +15529,13 @@ var casinoSpinExecutor = async (params, context) => {
15494
15529
  }
15495
15530
  const casinoWallet = getWalletAddress();
15496
15531
  if (!casinoWallet) {
15497
- return {
15498
- success: false,
15499
- error: "Casino wallet not initialized."
15500
- };
15532
+ return { success: false, error: "Casino wallet not initialized." };
15501
15533
  }
15502
15534
  const balanceInfo = await getWalletBalance(casinoWallet);
15503
15535
  if (!balanceInfo) {
15504
- return {
15505
- success: false,
15506
- error: "Failed to check casino balance."
15507
- };
15536
+ return { success: false, error: "Failed to check casino balance." };
15508
15537
  }
15509
15538
  const balance = parseFloat(balanceInfo.balance);
15510
- const jackpotMultiplier = CASINO_CONFIG.slot.jackpot.multiplier;
15511
15539
  if (balance < CASINO_CONFIG.minBankroll) {
15512
15540
  return {
15513
15541
  success: false,
@@ -15515,7 +15543,7 @@ var casinoSpinExecutor = async (params, context) => {
15515
15543
  };
15516
15544
  }
15517
15545
  const maxBetByPercent = balance * (CASINO_CONFIG.maxBetPercent / 100);
15518
- const maxBetByCoverage = balance / jackpotMultiplier;
15546
+ const maxBetByCoverage = balance / config.maxMultiplier;
15519
15547
  const maxBet = Math.min(maxBetByPercent, maxBetByCoverage);
15520
15548
  if (bet_amount > maxBet) {
15521
15549
  return {
@@ -15529,11 +15557,11 @@ var casinoSpinExecutor = async (params, context) => {
15529
15557
  error: `\u274C Minimum bet is ${CASINO_CONFIG.minBet} TON`
15530
15558
  };
15531
15559
  }
15532
- const cooldownCheck = checkCooldown(context.db, userId);
15560
+ const cooldownCheck = checkAndUpdateCooldown(context.db, userId);
15533
15561
  if (!cooldownCheck.allowed) {
15534
15562
  return {
15535
15563
  success: false,
15536
- error: cooldownCheck.message || "Please wait before spinning again."
15564
+ error: cooldownCheck.message || "Please wait before playing again."
15537
15565
  };
15538
15566
  }
15539
15567
  const requestTime = Date.now();
@@ -15541,9 +15569,8 @@ var casinoSpinExecutor = async (params, context) => {
15541
15569
  botWalletAddress: casinoWallet,
15542
15570
  betAmount: bet_amount,
15543
15571
  requestTime: requestTime - CASINO_CONFIG.paymentWindowMinutes * 60 * 1e3,
15544
- gameType: "slot",
15572
+ gameType: config.gameType,
15545
15573
  userId: username
15546
- // Use username for memo matching
15547
15574
  });
15548
15575
  if (!paymentVerification.verified || !paymentVerification.playerWallet) {
15549
15576
  return {
@@ -15552,76 +15579,74 @@ var casinoSpinExecutor = async (params, context) => {
15552
15579
  };
15553
15580
  }
15554
15581
  const playerWallet = paymentVerification.playerWallet;
15555
- updateCooldown(context.db, userId);
15556
15582
  const gramJsClient = context.bridge.getClient().getClient();
15557
- const spinResult = await gramJsClient.invoke(
15583
+ const result = await gramJsClient.invoke(
15558
15584
  new Api53.messages.SendMedia({
15559
15585
  peer: chat_id,
15560
- media: new Api53.InputMediaDice({ emoticon: "\u{1F3B0}" }),
15586
+ media: new Api53.InputMediaDice({ emoticon: config.emoticon }),
15561
15587
  message: "",
15562
15588
  randomId: BigInt(Math.floor(Math.random() * 1e16)),
15563
15589
  replyTo: reply_to ? new Api53.InputReplyToMessage({ replyToMsgId: reply_to }) : void 0
15564
15590
  })
15565
15591
  );
15566
- let slotValue;
15592
+ let gameValue;
15567
15593
  let messageId;
15568
- if (spinResult instanceof Api53.Updates || spinResult instanceof Api53.UpdatesCombined) {
15569
- for (const update of spinResult.updates) {
15594
+ if (result instanceof Api53.Updates || result instanceof Api53.UpdatesCombined) {
15595
+ for (const update of result.updates) {
15570
15596
  if (update instanceof Api53.UpdateNewMessage || update instanceof Api53.UpdateNewChannelMessage) {
15571
15597
  const msg = update.message;
15572
15598
  if (msg instanceof Api53.Message && msg.media instanceof Api53.MessageMediaDice) {
15573
- slotValue = msg.media.value;
15599
+ gameValue = msg.media.value;
15574
15600
  messageId = msg.id;
15575
15601
  break;
15576
15602
  }
15577
15603
  }
15578
15604
  }
15579
15605
  }
15580
- if (slotValue === void 0) {
15606
+ if (gameValue === void 0) {
15581
15607
  return {
15582
15608
  success: false,
15583
- error: "Failed to get slot result from Telegram."
15609
+ error: `Failed to get ${config.gameType} result from Telegram.`
15584
15610
  };
15585
15611
  }
15586
15612
  const houseEdge = processBetForJackpot(context.db, bet_amount);
15587
- context.db.prepare(
15588
- `
15589
- INSERT INTO casino_users (telegram_id, wallet_address, total_bets, total_wagered, last_bet_at)
15590
- VALUES (?, ?, 1, ?, unixepoch())
15591
- ON CONFLICT(telegram_id) DO UPDATE SET
15592
- wallet_address = excluded.wallet_address,
15593
- total_bets = total_bets + 1,
15594
- total_wagered = total_wagered + ?,
15595
- last_bet_at = unixepoch()
15596
- `
15597
- ).run(userId, playerWallet, bet_amount, bet_amount);
15598
- const journalEntry = context.db.prepare(
15599
- `
15600
- INSERT INTO journal (
15601
- type, action, asset_from, asset_to, amount_from,
15602
- platform, reasoning, outcome, tx_hash, tool_used,
15603
- chat_id, user_id, timestamp
15604
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, unixepoch())
15605
- `
15606
- ).run(
15607
- "trade",
15608
- "casino_spin",
15609
- "TON",
15610
- "SPIN",
15611
- bet_amount,
15612
- "telegram_casino",
15613
- `Slot spin result: ${slotValue}/64`,
15614
- "pending",
15615
- paymentVerification.txHash,
15616
- "casino_spin",
15617
- chat_id,
15618
- userId
15619
- );
15620
- const journalId = journalEntry.lastInsertRowid;
15621
- const multiplier = getSlotMultiplier(slotValue);
15613
+ const multiplier = config.getMultiplier(gameValue);
15622
15614
  const won = multiplier > 0;
15623
15615
  const payoutAmount = won ? bet_amount * multiplier : 0;
15624
15616
  const jackpot = getJackpot(context.db);
15617
+ const recordBet = context.db.transaction(() => {
15618
+ context.db.prepare(
15619
+ `INSERT INTO casino_users (telegram_id, wallet_address, total_bets, total_wagered, last_bet_at)
15620
+ VALUES (?, ?, 1, ?, unixepoch())
15621
+ ON CONFLICT(telegram_id) DO UPDATE SET
15622
+ wallet_address = excluded.wallet_address,
15623
+ total_bets = total_bets + 1,
15624
+ total_wagered = total_wagered + ?,
15625
+ last_bet_at = unixepoch()`
15626
+ ).run(userId, playerWallet, bet_amount, bet_amount);
15627
+ const journalEntry = context.db.prepare(
15628
+ `INSERT INTO journal (
15629
+ type, action, asset_from, asset_to, amount_from,
15630
+ platform, reasoning, outcome, tx_hash, tool_used,
15631
+ chat_id, user_id, timestamp
15632
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, unixepoch())`
15633
+ ).run(
15634
+ "trade",
15635
+ config.toolName,
15636
+ "TON",
15637
+ config.assetLabel,
15638
+ bet_amount,
15639
+ "telegram_casino",
15640
+ `${config.gameType} result: ${gameValue}/${config.maxValue}`,
15641
+ "pending",
15642
+ paymentVerification.txHash,
15643
+ config.toolName,
15644
+ chat_id,
15645
+ userId
15646
+ );
15647
+ return journalEntry.lastInsertRowid;
15648
+ });
15649
+ const journalId = recordBet();
15625
15650
  let payoutSent = false;
15626
15651
  let payoutTxHash;
15627
15652
  if (won && payoutAmount > 0) {
@@ -15630,41 +15655,30 @@ var casinoSpinExecutor = async (params, context) => {
15630
15655
  if (payoutResult.success) {
15631
15656
  payoutSent = true;
15632
15657
  payoutTxHash = payoutResult.txHash;
15633
- context.db.prepare(
15634
- `UPDATE journal
15635
- SET outcome = 'loss',
15636
- amount_to = ?,
15637
- pnl_ton = ?,
15638
- closed_at = unixepoch()
15639
- WHERE id = ?`
15640
- ).run(payoutAmount, -(payoutAmount - bet_amount), journalId);
15641
- context.db.prepare(
15642
- `UPDATE casino_users
15643
- SET total_wins = total_wins + 1,
15644
- total_won = total_won + ?
15645
- WHERE telegram_id = ?`
15646
- ).run(payoutAmount, oddsId);
15658
+ const recordWin = context.db.transaction(() => {
15659
+ context.db.prepare(
15660
+ `UPDATE journal SET outcome = 'loss', amount_to = ?, pnl_ton = ?, closed_at = unixepoch() WHERE id = ?`
15661
+ ).run(payoutAmount, -(payoutAmount - bet_amount), journalId);
15662
+ context.db.prepare(
15663
+ `UPDATE casino_users SET total_wins = total_wins + 1, total_won = total_won + ? WHERE telegram_id = ?`
15664
+ ).run(payoutAmount, userId);
15665
+ });
15666
+ recordWin();
15647
15667
  }
15648
15668
  } else {
15649
- context.db.prepare(
15650
- `UPDATE journal
15651
- SET outcome = 'profit',
15652
- amount_to = 0,
15653
- pnl_ton = ?,
15654
- closed_at = unixepoch()
15655
- WHERE id = ?`
15656
- ).run(bet_amount, journalId);
15657
- context.db.prepare(
15658
- `UPDATE casino_users
15659
- SET total_losses = total_losses + 1
15660
- WHERE telegram_id = ?`
15661
- ).run(oddsId);
15669
+ const recordLoss = context.db.transaction(() => {
15670
+ context.db.prepare(
15671
+ `UPDATE journal SET outcome = 'profit', amount_to = 0, pnl_ton = ?, closed_at = unixepoch() WHERE id = ?`
15672
+ ).run(bet_amount, journalId);
15673
+ context.db.prepare(`UPDATE casino_users SET total_losses = total_losses + 1 WHERE telegram_id = ?`).run(userId);
15674
+ });
15675
+ recordLoss();
15662
15676
  }
15663
- const interpretation = getSlotInterpretation(slotValue);
15677
+ const interpretation = config.getInterpretation(gameValue);
15664
15678
  return {
15665
15679
  success: true,
15666
15680
  data: {
15667
- slot_value: slotValue,
15681
+ game_value: gameValue,
15668
15682
  won,
15669
15683
  multiplier,
15670
15684
  payout_amount: payoutAmount > 0 ? payoutAmount.toFixed(2) : "0",
@@ -15682,17 +15696,73 @@ var casinoSpinExecutor = async (params, context) => {
15682
15696
  }
15683
15697
  };
15684
15698
  } catch (error) {
15685
- console.error("Error in casino_spin:", error);
15699
+ console.error(`Error in ${config.toolName}:`, error);
15686
15700
  return {
15687
15701
  success: false,
15688
15702
  error: error instanceof Error ? error.message : String(error)
15689
15703
  };
15690
15704
  }
15705
+ }
15706
+
15707
+ // src/agent/tools/casino/spin.ts
15708
+ var casinoSpinTool = {
15709
+ name: "casino_spin",
15710
+ description: `Execute a Teleton Casino slot machine spin with full security checks.
15711
+
15712
+ Slot payout table (40% house edge):
15713
+ - \u{1F3B0} 64 (777) = JACKPOT (5x bet)
15714
+ - \u{1F3B0} 60-63 = Big win (2.5x bet)
15715
+ - \u{1F3B0} 55-59 = Medium win (1.8x bet)
15716
+ - \u{1F3B0} 43-54 = Small win (1.2x bet)
15717
+ - \u{1F3B0} 1-42 = No win
15718
+
15719
+ Process:
15720
+ 1. Validates bet amount (min 0.1 TON, max 5% of bankroll)
15721
+ 2. Checks user cooldown (30 seconds between spins)
15722
+ 3. Verifies TON payment with username as memo
15723
+ 4. Auto-discovers player wallet from transaction
15724
+ 5. Sends \u{1F3B0} slot machine animation
15725
+ 6. Processes house edge (5%) to daily jackpot
15726
+ 7. AUTO-PAYOUT if player wins
15727
+
15728
+ Tell the user: "Send X TON to [casino_address] with memo: your_username"`,
15729
+ parameters: Type106.Object({
15730
+ chat_id: Type106.String({
15731
+ description: "Telegram chat ID where to send the spin"
15732
+ }),
15733
+ bet_amount: Type106.Number({
15734
+ description: "Bet amount in TON",
15735
+ minimum: 0.1
15736
+ }),
15737
+ player_username: Type106.String({
15738
+ description: "Player's Telegram username (without @)"
15739
+ }),
15740
+ reply_to: Type106.Optional(
15741
+ Type106.Number({
15742
+ description: "Message ID to reply to"
15743
+ })
15744
+ )
15745
+ })
15746
+ };
15747
+ var casinoSpinExecutor = async (params, context) => {
15748
+ return executeGame(
15749
+ {
15750
+ emoticon: "\u{1F3B0}",
15751
+ gameType: "slot",
15752
+ toolName: "casino_spin",
15753
+ assetLabel: "SPIN",
15754
+ maxMultiplier: CASINO_CONFIG.slot.jackpot.multiplier,
15755
+ getMultiplier: getSlotMultiplier,
15756
+ getInterpretation: getSlotInterpretation,
15757
+ maxValue: 64
15758
+ },
15759
+ params,
15760
+ context
15761
+ );
15691
15762
  };
15692
15763
 
15693
15764
  // src/agent/tools/casino/dice.ts
15694
15765
  import { Type as Type107 } from "@sinclair/typebox";
15695
- import { Api as Api54 } from "telegram";
15696
15766
  var casinoDiceTool = {
15697
15767
  name: "casino_dice",
15698
15768
  description: `Execute a Teleton Casino dice roll with full security checks.
@@ -15711,7 +15781,7 @@ Same security as slot:
15711
15781
  5. Sends \u{1F3B2} dice animation
15712
15782
  6. AUTO-PAYOUT if player wins
15713
15783
 
15714
- Tell the user: "Send X TON to EQxxx with memo: your_username"`,
15784
+ Tell the user: "Send X TON to [casino_address] with memo: your_username"`,
15715
15785
  parameters: Type107.Object({
15716
15786
  chat_id: Type107.String({
15717
15787
  description: "Telegram chat ID where to send the dice"
@@ -15731,197 +15801,20 @@ Tell the user: "Send X TON to EQxxx with memo: your_username"`,
15731
15801
  })
15732
15802
  };
15733
15803
  var casinoDiceExecutor = async (params, context) => {
15734
- try {
15735
- const { chat_id, bet_amount, player_username, reply_to } = params;
15736
- const oddsId = context.senderId.toString();
15737
- const username = player_username?.replace(/^@/, "").toLowerCase().trim();
15738
- if (!username || username.length === 0) {
15739
- return {
15740
- success: false,
15741
- error: "\u274C You need a Telegram @username to play at Teleton Casino. Set up your username in Telegram settings and try again!"
15742
- };
15743
- }
15744
- const rateCheck = checkRateLimit(oddsId, "casino_dice");
15745
- if (!rateCheck.allowed) {
15746
- return {
15747
- success: false,
15748
- error: rateCheck.message || "Too many attempts. Please wait."
15749
- };
15750
- }
15751
- const casinoWallet = getWalletAddress();
15752
- if (!casinoWallet) {
15753
- return {
15754
- success: false,
15755
- error: "Casino wallet not initialized."
15756
- };
15757
- }
15758
- const balanceInfo = await getWalletBalance(casinoWallet);
15759
- if (!balanceInfo) {
15760
- return {
15761
- success: false,
15762
- error: "Failed to check casino balance."
15763
- };
15764
- }
15765
- const balance = parseFloat(balanceInfo.balance);
15766
- if (balance < CASINO_CONFIG.minBankroll) {
15767
- return {
15768
- success: false,
15769
- error: "\u{1F6A8} Teleton Casino is temporarily closed (insufficient bankroll)."
15770
- };
15771
- }
15772
- const diceMaxMultiplier = CASINO_CONFIG.dice.jackpot.multiplier;
15773
- const maxBetByPercent = balance * (CASINO_CONFIG.maxBetPercent / 100);
15774
- const maxBetByCoverage = balance / diceMaxMultiplier;
15775
- const maxBet = Math.min(maxBetByPercent, maxBetByCoverage);
15776
- if (bet_amount > maxBet) {
15777
- return {
15778
- success: false,
15779
- error: `\u274C Bet too high. Maximum bet: ${maxBet.toFixed(2)} TON`
15780
- };
15781
- }
15782
- if (bet_amount < CASINO_CONFIG.minBet) {
15783
- return {
15784
- success: false,
15785
- error: `\u274C Minimum bet is ${CASINO_CONFIG.minBet} TON`
15786
- };
15787
- }
15788
- const cooldownCheck = checkCooldown(context.db, oddsId);
15789
- if (!cooldownCheck.allowed) {
15790
- return {
15791
- success: false,
15792
- error: cooldownCheck.message || "Please wait before rolling again."
15793
- };
15794
- }
15795
- const requestTime = Date.now();
15796
- const paymentVerification = await verifyPayment(context.db, {
15797
- botWalletAddress: casinoWallet,
15798
- betAmount: bet_amount,
15799
- requestTime: requestTime - CASINO_CONFIG.paymentWindowMinutes * 60 * 1e3,
15804
+ return executeGame(
15805
+ {
15806
+ emoticon: "\u{1F3B2}",
15800
15807
  gameType: "dice",
15801
- userId: username
15802
- });
15803
- if (!paymentVerification.verified || !paymentVerification.playerWallet) {
15804
- return {
15805
- success: false,
15806
- error: paymentVerification.error || `\u274C Payment not found. Send ${bet_amount} TON to ${casinoWallet} with memo: ${username}`
15807
- };
15808
- }
15809
- const playerWallet = paymentVerification.playerWallet;
15810
- updateCooldown(context.db, oddsId);
15811
- const gramJsClient = context.bridge.getClient().getClient();
15812
- const diceResult = await gramJsClient.invoke(
15813
- new Api54.messages.SendMedia({
15814
- peer: chat_id,
15815
- media: new Api54.InputMediaDice({ emoticon: "\u{1F3B2}" }),
15816
- message: "",
15817
- randomId: BigInt(Math.floor(Math.random() * 1e16)),
15818
- replyTo: reply_to ? new Api54.InputReplyToMessage({ replyToMsgId: reply_to }) : void 0
15819
- })
15820
- );
15821
- let diceValue;
15822
- let messageId;
15823
- if (diceResult instanceof Api54.Updates || diceResult instanceof Api54.UpdatesCombined) {
15824
- for (const update of diceResult.updates) {
15825
- if (update instanceof Api54.UpdateNewMessage || update instanceof Api54.UpdateNewChannelMessage) {
15826
- const msg = update.message;
15827
- if (msg instanceof Api54.Message && msg.media instanceof Api54.MessageMediaDice) {
15828
- diceValue = msg.media.value;
15829
- messageId = msg.id;
15830
- break;
15831
- }
15832
- }
15833
- }
15834
- }
15835
- if (diceValue === void 0) {
15836
- return {
15837
- success: false,
15838
- error: "Failed to get dice result from Telegram."
15839
- };
15840
- }
15841
- const houseEdge = processBetForJackpot(context.db, bet_amount);
15842
- context.db.prepare(
15843
- `INSERT INTO casino_users (telegram_id, wallet_address, total_bets, total_wagered, last_bet_at)
15844
- VALUES (?, ?, 1, ?, unixepoch())
15845
- ON CONFLICT(telegram_id) DO UPDATE SET
15846
- wallet_address = excluded.wallet_address,
15847
- total_bets = total_bets + 1,
15848
- total_wagered = total_wagered + ?,
15849
- last_bet_at = unixepoch()`
15850
- ).run(oddsId, playerWallet, bet_amount, bet_amount);
15851
- const journalEntry = context.db.prepare(
15852
- `INSERT INTO journal (
15853
- type, action, asset_from, asset_to, amount_from,
15854
- platform, reasoning, outcome, tx_hash, tool_used,
15855
- chat_id, user_id, timestamp
15856
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, unixepoch())`
15857
- ).run(
15858
- "trade",
15859
- "casino_dice",
15860
- "TON",
15861
- "DICE",
15862
- bet_amount,
15863
- "telegram_casino",
15864
- `Dice roll result: ${diceValue}/6`,
15865
- "pending",
15866
- paymentVerification.txHash,
15867
- "casino_dice",
15868
- chat_id,
15869
- oddsId
15870
- );
15871
- const journalId = journalEntry.lastInsertRowid;
15872
- const multiplier = getDiceMultiplier(diceValue);
15873
- const won = multiplier > 0;
15874
- const payoutAmount = won ? bet_amount * multiplier : 0;
15875
- const jackpot = getJackpot(context.db);
15876
- let payoutSent = false;
15877
- let payoutTxHash;
15878
- if (won && payoutAmount > 0) {
15879
- const winMessage = getWinMessage(multiplier, payoutAmount);
15880
- const payoutResult = await sendPayout(playerWallet, payoutAmount, winMessage);
15881
- if (payoutResult.success) {
15882
- payoutSent = true;
15883
- payoutTxHash = payoutResult.txHash;
15884
- context.db.prepare(
15885
- `UPDATE journal SET outcome = 'loss', amount_to = ?, pnl_ton = ?, closed_at = unixepoch() WHERE id = ?`
15886
- ).run(payoutAmount, -(payoutAmount - bet_amount), journalId);
15887
- context.db.prepare(
15888
- `UPDATE casino_users SET total_wins = total_wins + 1, total_won = total_won + ? WHERE telegram_id = ?`
15889
- ).run(payoutAmount, oddsId);
15890
- }
15891
- } else {
15892
- context.db.prepare(
15893
- `UPDATE journal SET outcome = 'profit', amount_to = 0, pnl_ton = ?, closed_at = unixepoch() WHERE id = ?`
15894
- ).run(bet_amount, journalId);
15895
- context.db.prepare(`UPDATE casino_users SET total_losses = total_losses + 1 WHERE telegram_id = ?`).run(oddsId);
15896
- }
15897
- const interpretation = getDiceInterpretation(diceValue);
15898
- return {
15899
- success: true,
15900
- data: {
15901
- dice_value: diceValue,
15902
- won,
15903
- multiplier,
15904
- payout_amount: payoutAmount > 0 ? payoutAmount.toFixed(2) : "0",
15905
- payout_sent: payoutSent,
15906
- payout_tx_hash: payoutTxHash,
15907
- bet_amount: bet_amount.toFixed(2),
15908
- player_username: username,
15909
- player_wallet: playerWallet,
15910
- house_edge: houseEdge.toFixed(2),
15911
- current_jackpot: jackpot.amount.toFixed(2),
15912
- payment_tx_hash: paymentVerification.txHash,
15913
- journal_id: journalId,
15914
- message_id: messageId,
15915
- interpretation
15916
- }
15917
- };
15918
- } catch (error) {
15919
- console.error("Error in casino_dice:", error);
15920
- return {
15921
- success: false,
15922
- error: error instanceof Error ? error.message : String(error)
15923
- };
15924
- }
15808
+ toolName: "casino_dice",
15809
+ assetLabel: "DICE",
15810
+ maxMultiplier: CASINO_CONFIG.dice.jackpot.multiplier,
15811
+ getMultiplier: getDiceMultiplier,
15812
+ getInterpretation: getDiceInterpretation,
15813
+ maxValue: 6
15814
+ },
15815
+ params,
15816
+ context
15817
+ );
15925
15818
  };
15926
15819
 
15927
15820
  // src/agent/tools/casino/payout.ts
@@ -16143,6 +16036,12 @@ Shows:
16143
16036
  var casinoLeaderboardExecutor = async (params, context) => {
16144
16037
  try {
16145
16038
  const { limit = 10, type = "winners" } = params;
16039
+ const ORDER_BY = {
16040
+ winners: "total_pnl DESC",
16041
+ losers: "total_pnl ASC",
16042
+ wagered: "cu.total_wagered DESC"
16043
+ };
16044
+ const orderBy = ORDER_BY[type] ?? ORDER_BY.winners;
16146
16045
  const query = `
16147
16046
  SELECT
16148
16047
  cu.telegram_id,
@@ -16157,7 +16056,7 @@ var casinoLeaderboardExecutor = async (params, context) => {
16157
16056
  LEFT JOIN journal j ON j.user_id = cu.telegram_id AND j.type = 'trade' AND j.action = 'casino_spin'
16158
16057
  WHERE cu.total_bets > 0
16159
16058
  GROUP BY cu.telegram_id
16160
- ORDER BY ${type === "winners" ? "total_pnl DESC" : type === "losers" ? "total_pnl ASC" : "cu.total_wagered DESC"}
16059
+ ORDER BY ${orderBy}
16161
16060
  LIMIT ?
16162
16061
  `;
16163
16062
  const leaderboard = context.db.prepare(query).all(limit);
@@ -16795,11 +16694,11 @@ To confirm, type: @${botUsername} ${dealId}` : proposalText;
16795
16694
  };
16796
16695
  async function sendInlineBotResult(bridge, chatId, botUsername, dealId) {
16797
16696
  const gramJsClient = bridge.getClient().getClient();
16798
- const Api55 = (await import("telegram")).Api;
16697
+ const Api58 = (await import("telegram")).Api;
16799
16698
  const bot = await gramJsClient.getInputEntity(botUsername);
16800
16699
  const peer = await gramJsClient.getInputEntity(chatId.startsWith("-") ? Number(chatId) : chatId);
16801
16700
  const results = await gramJsClient.invoke(
16802
- new Api55.messages.GetInlineBotResults({
16701
+ new Api58.messages.GetInlineBotResults({
16803
16702
  bot,
16804
16703
  peer,
16805
16704
  query: dealId,
@@ -16813,7 +16712,7 @@ async function sendInlineBotResult(bridge, chatId, botUsername, dealId) {
16813
16712
  const dealResult = results.results.find((r) => r.id === dealId);
16814
16713
  const resultToSend = dealResult || results.results[0];
16815
16714
  await gramJsClient.invoke(
16816
- new Api55.messages.SendInlineBotResult({
16715
+ new Api58.messages.SendInlineBotResult({
16817
16716
  peer,
16818
16717
  queryId: results.queryId,
16819
16718
  id: resultToSend.id,
@@ -16840,7 +16739,7 @@ var GiftDetector = class {
16840
16739
  const result = await telegramGetMyGiftsExecutor(
16841
16740
  {
16842
16741
  userId: userId.toString(),
16843
- limit: 50
16742
+ limit: DEFAULT_GIFTS_QUERY_LIMIT
16844
16743
  },
16845
16744
  context
16846
16745
  );
@@ -17024,15 +16923,15 @@ Thank you for trading! \u{1F389}`
17024
16923
  `\u{1F381} [Deal] Sending gift ${deal.agent_gives_gift_slug} (msgId: ${deal.agent_gives_gift_id}) to user ${deal.user_telegram_id}...`
17025
16924
  );
17026
16925
  const gramJsClient = bridge.getClient().getClient();
17027
- const Api55 = (await import("telegram")).Api;
16926
+ const Api58 = (await import("telegram")).Api;
17028
16927
  try {
17029
16928
  const toUser = await gramJsClient.getInputEntity(deal.user_telegram_id);
17030
- const stargiftInput = new Api55.InputSavedStarGiftUser({
16929
+ const stargiftInput = new Api58.InputSavedStarGiftUser({
17031
16930
  msgId: parseInt(deal.agent_gives_gift_id, 10)
17032
16931
  });
17033
16932
  try {
17034
16933
  await gramJsClient.invoke(
17035
- new Api55.payments.TransferStarGift({
16934
+ new Api58.payments.TransferStarGift({
17036
16935
  stargift: stargiftInput,
17037
16936
  toId: toUser
17038
16937
  })
@@ -17040,17 +16939,17 @@ Thank you for trading! \u{1F389}`
17040
16939
  } catch (freeTransferError) {
17041
16940
  if (freeTransferError?.errorMessage === "PAYMENT_REQUIRED") {
17042
16941
  console.log("Transfer requires payment, using payment flow...");
17043
- const invoice = new Api55.InputInvoiceStarGiftTransfer({
16942
+ const invoice = new Api58.InputInvoiceStarGiftTransfer({
17044
16943
  stargift: stargiftInput,
17045
16944
  toId: toUser
17046
16945
  });
17047
16946
  const form = await gramJsClient.invoke(
17048
- new Api55.payments.GetPaymentForm({
16947
+ new Api58.payments.GetPaymentForm({
17049
16948
  invoice
17050
16949
  })
17051
16950
  );
17052
16951
  await gramJsClient.invoke(
17053
- new Api55.payments.SendStarsForm({
16952
+ new Api58.payments.SendStarsForm({
17054
16953
  formId: form.formId,
17055
16954
  invoice
17056
16955
  })
@@ -17607,8 +17506,138 @@ No payment has been processed. You can propose a new deal if you'd like.`
17607
17506
  }
17608
17507
  };
17609
17508
 
17509
+ // src/agent/tools/register-all.ts
17510
+ function registerAllTools(registry, config) {
17511
+ registry.register(telegramSendMessageTool, telegramSendMessageExecutor);
17512
+ registry.register(telegramQuoteReplyTool, telegramQuoteReplyExecutor);
17513
+ registry.register(telegramGetRepliesTool, telegramGetRepliesExecutor);
17514
+ registry.register(telegramEditMessageTool, telegramEditMessageExecutor);
17515
+ registry.register(telegramScheduleMessageTool, telegramScheduleMessageExecutor);
17516
+ registry.register(telegramCreateScheduledTaskTool, telegramCreateScheduledTaskExecutor);
17517
+ registry.register(telegramSearchMessagesTool, telegramSearchMessagesExecutor);
17518
+ registry.register(telegramPinMessageTool, telegramPinMessageExecutor);
17519
+ registry.register(telegramUnpinMessageTool, telegramUnpinMessageExecutor);
17520
+ registry.register(telegramReactTool, telegramReactExecutor);
17521
+ registry.register(telegramSendDiceTool, telegramSendDiceExecutor);
17522
+ registry.register(telegramForwardMessageTool, telegramForwardMessageExecutor);
17523
+ registry.register(telegramSendPhotoTool, telegramSendPhotoExecutor);
17524
+ registry.register(telegramSendVoiceTool, telegramSendVoiceExecutor);
17525
+ registry.register(telegramSendStickerTool, telegramSendStickerExecutor);
17526
+ registry.register(telegramSendGifTool, telegramSendGifExecutor);
17527
+ registry.register(telegramCreatePollTool, telegramCreatePollExecutor);
17528
+ registry.register(telegramCreateQuizTool, telegramCreateQuizExecutor);
17529
+ registry.register(telegramReplyKeyboardTool, telegramReplyKeyboardExecutor);
17530
+ registry.register(telegramSearchStickersTool, telegramSearchStickersExecutor);
17531
+ registry.register(telegramGetMyStickersTool, telegramGetMyStickersExecutor);
17532
+ registry.register(telegramSearchGifsTool, telegramSearchGifsExecutor);
17533
+ registry.register(telegramAddStickerSetTool, telegramAddStickerSetExecutor);
17534
+ registry.register(telegramGetHistoryTool, telegramGetHistoryExecutor);
17535
+ registry.register(telegramGetDialogsTool, telegramGetDialogsExecutor);
17536
+ registry.register(telegramMarkAsReadTool, telegramMarkAsReadExecutor);
17537
+ registry.register(telegramGetChatInfoTool, telegramGetChatInfoExecutor);
17538
+ registry.register(telegramJoinChannelTool, telegramJoinChannelExecutor);
17539
+ registry.register(telegramLeaveChannelTool, telegramLeaveChannelExecutor);
17540
+ registry.register(telegramGetMeTool, telegramGetMeExecutor);
17541
+ registry.register(telegramGetParticipantsTool, telegramGetParticipantsExecutor);
17542
+ registry.register(telegramKickUserTool, telegramKickUserExecutor);
17543
+ registry.register(telegramBanUserTool, telegramBanUserExecutor);
17544
+ registry.register(telegramUnbanUserTool, telegramUnbanUserExecutor);
17545
+ registry.register(telegramCreateGroupTool, telegramCreateGroupExecutor);
17546
+ registry.register(telegramSetChatPhotoTool, telegramSetChatPhotoExecutor);
17547
+ registry.register(telegramBlockUserTool, telegramBlockUserExecutor);
17548
+ registry.register(telegramGetBlockedTool, telegramGetBlockedExecutor);
17549
+ registry.register(telegramGetCommonChatsTool, telegramGetCommonChatsExecutor);
17550
+ registry.register(telegramSendStoryTool, telegramSendStoryExecutor);
17551
+ registry.register(telegramGetFoldersTool, telegramGetFoldersExecutor);
17552
+ registry.register(telegramCreateFolderTool, telegramCreateFolderExecutor);
17553
+ registry.register(telegramAddChatToFolderTool, telegramAddChatToFolderExecutor);
17554
+ registry.register(telegramCreateChannelTool, telegramCreateChannelExecutor);
17555
+ registry.register(telegramUpdateProfileTool, telegramUpdateProfileExecutor);
17556
+ registry.register(telegramSetBioTool, telegramSetBioExecutor);
17557
+ registry.register(telegramSetUsernameTool, telegramSetUsernameExecutor);
17558
+ registry.register(telegramDeleteMessageTool, telegramDeleteMessageExecutor);
17559
+ registry.register(telegramDownloadMediaTool, telegramDownloadMediaExecutor);
17560
+ registry.register(visionAnalyzeTool, visionAnalyzeExecutor);
17561
+ registry.register(telegramGetStarsBalanceTool, telegramGetStarsBalanceExecutor);
17562
+ registry.register(telegramGetStarsTransactionsTool, telegramGetStarsTransactionsExecutor);
17563
+ registry.register(telegramGetAvailableGiftsTool, telegramGetAvailableGiftsExecutor);
17564
+ registry.register(telegramSendGiftTool, telegramSendGiftExecutor);
17565
+ registry.register(telegramGetMyGiftsTool, telegramGetMyGiftsExecutor);
17566
+ registry.register(telegramTransferCollectibleTool, telegramTransferCollectibleExecutor);
17567
+ registry.register(telegramSetCollectiblePriceTool, telegramSetCollectiblePriceExecutor);
17568
+ registry.register(telegramGetResaleGiftsTool, telegramGetResaleGiftsExecutor);
17569
+ registry.register(telegramBuyResaleGiftTool, telegramBuyResaleGiftExecutor);
17570
+ registry.register(telegramSetGiftStatusTool, telegramSetGiftStatusExecutor);
17571
+ registry.register(memoryWriteTool, memoryWriteExecutor);
17572
+ registry.register(memoryReadTool, memoryReadExecutor);
17573
+ registry.register(telegramGetUserInfoTool, telegramGetUserInfoExecutor);
17574
+ registry.register(telegramCheckUsernameTool, telegramCheckUsernameExecutor);
17575
+ registry.register(telegramEditChannelInfoTool, telegramEditChannelInfoExecutor);
17576
+ registry.register(telegramInviteToChannelTool, telegramInviteToChannelExecutor);
17577
+ registry.register(marketGetFloorTool, marketGetFloorExecutor);
17578
+ registry.register(marketSearchTool, marketSearchExecutor);
17579
+ registry.register(marketCheapestTool, marketCheapestExecutor);
17580
+ registry.register(marketPriceHistoryTool, marketPriceHistoryExecutor);
17581
+ registry.register(tonGetAddressTool, tonGetAddressExecutor);
17582
+ registry.register(tonGetBalanceTool, tonGetBalanceExecutor);
17583
+ registry.register(tonPriceTool, tonPriceExecutor);
17584
+ registry.register(tonSendTool, tonSendExecutor);
17585
+ registry.register(tonGetTransactionsTool, tonGetTransactionsExecutor);
17586
+ registry.register(tonMyTransactionsTool, tonMyTransactionsExecutor);
17587
+ registry.register(jettonBalancesTool, jettonBalancesExecutor);
17588
+ registry.register(jettonSwapTool, jettonSwapExecutor);
17589
+ registry.register(jettonSendTool, jettonSendExecutor);
17590
+ registry.register(jettonInfoTool, jettonInfoExecutor);
17591
+ registry.register(jettonPriceTool, jettonPriceExecutor);
17592
+ registry.register(jettonSearchTool, jettonSearchExecutor);
17593
+ registry.register(jettonQuoteTool, jettonQuoteExecutor);
17594
+ registry.register(jettonHoldersTool, jettonHoldersExecutor);
17595
+ registry.register(jettonHistoryTool, jettonHistoryExecutor);
17596
+ registry.register(jettonTrendingTool, jettonTrendingExecutor);
17597
+ registry.register(jettonPoolsTool, jettonPoolsExecutor);
17598
+ registry.register(dnsCheckTool, dnsCheckExecutor);
17599
+ registry.register(dnsAuctionsTool, dnsAuctionsExecutor);
17600
+ registry.register(dnsResolveTool, dnsResolveExecutor);
17601
+ registry.register(dnsStartAuctionTool, dnsStartAuctionExecutor);
17602
+ registry.register(dnsBidTool, dnsBidExecutor);
17603
+ registry.register(dnsLinkTool, dnsLinkExecutor);
17604
+ registry.register(dnsUnlinkTool, dnsUnlinkExecutor);
17605
+ registry.register(dedustQuoteTool, dedustQuoteExecutor);
17606
+ registry.register(dedustSwapTool, dedustSwapExecutor);
17607
+ registry.register(dedustPoolsTool, dedustPoolsExecutor);
17608
+ registry.register(dexQuoteTool, dexQuoteExecutor);
17609
+ registry.register(dexSwapTool, dexSwapExecutor);
17610
+ registry.register(journalLogTool, journalLogExecutor);
17611
+ registry.register(journalQueryTool, journalQueryExecutor);
17612
+ registry.register(journalUpdateTool, journalUpdateExecutor);
17613
+ registry.register(workspaceListTool, workspaceListExecutor);
17614
+ registry.register(workspaceReadTool, workspaceReadExecutor);
17615
+ registry.register(workspaceWriteTool, workspaceWriteExecutor);
17616
+ registry.register(workspaceDeleteTool, workspaceDeleteExecutor);
17617
+ registry.register(workspaceInfoTool, workspaceInfoExecutor);
17618
+ registry.register(workspaceRenameTool, workspaceRenameExecutor);
17619
+ if (config.casino.enabled) {
17620
+ registry.register(casinoBalanceTool, casinoBalanceExecutor);
17621
+ registry.register(casinoSpinTool, casinoSpinExecutor);
17622
+ registry.register(casinoDiceTool, casinoDiceExecutor);
17623
+ registry.register(casinoPayoutTool, casinoPayoutExecutor);
17624
+ registry.register(casinoLeaderboardTool, casinoLeaderboardExecutor);
17625
+ registry.register(casinoMyStatsTool, casinoMyStatsExecutor);
17626
+ registry.register(casinoJackpotInfoTool, casinoJackpotInfoExecutor);
17627
+ registry.register(casinoAwardJackpotTool, casinoAwardJackpotExecutor);
17628
+ }
17629
+ if (config.deals.enabled) {
17630
+ registry.register(dealProposeTool, dealProposeExecutor);
17631
+ registry.register(dealVerifyPaymentTool, dealVerifyPaymentExecutor);
17632
+ registry.register(dealStatusTool, dealStatusExecutor);
17633
+ registry.register(dealListTool, dealListExecutor);
17634
+ registry.register(dealCancelTool, dealCancelExecutor);
17635
+ }
17636
+ }
17637
+
17610
17638
  // src/bot/index.ts
17611
17639
  import { Bot } from "grammy";
17640
+ import { Api as Api57 } from "telegram";
17612
17641
 
17613
17642
  // src/bot/types.ts
17614
17643
  function decodeCallback(raw) {
@@ -17658,7 +17687,7 @@ function getDeal(db, dealId) {
17658
17687
  };
17659
17688
  }
17660
17689
  function acceptDeal(db, dealId) {
17661
- const newExpiry = Math.floor(Date.now() / 1e3) + 300;
17690
+ const newExpiry = Math.floor(Date.now() / 1e3) + DEAL_VERIFICATION_WINDOW_SECONDS;
17662
17691
  db.prepare(`UPDATE deals SET status = 'accepted', expires_at = ? WHERE id = ?`).run(
17663
17692
  newExpiry,
17664
17693
  dealId
@@ -17745,10 +17774,10 @@ function updateUserStats(db, userId, username, deal, completed) {
17745
17774
  }
17746
17775
 
17747
17776
  // src/bot/services/message-builder.ts
17748
- import { InlineKeyboard } from "grammy";
17749
17777
  function esc(text) {
17750
17778
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
17751
17779
  }
17780
+ var TIMER_EMOJI = `<tg-emoji emoji-id="5451646226975955576">\u23F3</tg-emoji>`;
17752
17781
  function formatAsset2(type, tonAmount, giftSlug) {
17753
17782
  if (type === "ton" && tonAmount) {
17754
17783
  return `<b>${tonAmount} TON</b>`;
@@ -17779,14 +17808,19 @@ function buildProposalMessage(deal) {
17779
17808
  );
17780
17809
  const remaining = getRemainingTime(deal.expiresAt);
17781
17810
  const user = deal.username ? `@${esc(deal.username)}` : `${deal.userId}`;
17782
- const text = `\u{1F4CB} <b>Deal</b> #${esc(deal.dealId)}
17811
+ const text = `\u{1F45B} <b>Deal</b> #${esc(deal.dealId)}
17783
17812
 
17784
17813
  \u{1F464} ${user}
17785
17814
  \u{1F4E4} Sends: ${userGives}
17786
17815
  \u{1F4E5} Receives: ${agentGives}
17787
- \u23F1 Expires in ${remaining}`;
17788
- const keyboard = new InlineKeyboard().text("\u2705 Accept", `accept:${deal.dealId}`).text("\u274C Decline", `decline:${deal.dealId}`);
17789
- return { text, keyboard };
17816
+ ${TIMER_EMOJI} Expires in ${remaining}`;
17817
+ const buttons = [
17818
+ [
17819
+ { text: "\u2705 Accept", callbackData: `accept:${deal.dealId}`, style: "success" },
17820
+ { text: "\u274C Decline", callbackData: `decline:${deal.dealId}`, style: "danger" }
17821
+ ]
17822
+ ];
17823
+ return { text, buttons };
17790
17824
  }
17791
17825
  function buildAcceptedMessage(deal, agentWallet) {
17792
17826
  const userGives = formatAsset2(
@@ -17800,38 +17834,48 @@ function buildAcceptedMessage(deal, agentWallet) {
17800
17834
  deal.agentGivesGiftSlug
17801
17835
  );
17802
17836
  let instructions;
17803
- let keyboard;
17837
+ let buttons;
17804
17838
  if (deal.userGivesType === "ton") {
17805
17839
  instructions = `
17806
17840
  \u{1F4B0} <b>Send ${deal.userGivesTonAmount} TON</b>
17807
17841
  \u{1F4CD} <code>${esc(agentWallet)}</code>
17808
17842
  \u{1F4DD} Memo: <code>${esc(deal.dealId)}</code>
17809
17843
 
17810
- \u26A0\uFE0F <b>Memo is required!</b>`;
17811
- keyboard = new InlineKeyboard().text("\u{1F4CB} Copy Address", `copy_addr:${deal.dealId}`).text("\u{1F4CB} Copy Memo", `copy_memo:${deal.dealId}`).row().text("\u2705 I've sent the payment", `sent:${deal.dealId}`);
17844
+ \u203C\uFE0F <b>Memo is required!</b>`;
17845
+ buttons = [
17846
+ [
17847
+ { text: "Copy Address", callbackData: `copy_addr:${deal.dealId}`, copyText: agentWallet },
17848
+ { text: "Copy Memo", callbackData: `copy_memo:${deal.dealId}`, copyText: deal.dealId }
17849
+ ],
17850
+ [{ text: "\u2705 I've sent the payment", callbackData: `sent:${deal.dealId}`, style: "primary" }]
17851
+ ];
17812
17852
  } else {
17813
17853
  instructions = `
17814
17854
  \u{1F381} Send your ${formatAsset2("gift", void 0, deal.userGivesGiftSlug)} to the agent`;
17815
- keyboard = new InlineKeyboard().text("\u2705 I've sent the gift", `sent:${deal.dealId}`);
17855
+ buttons = [
17856
+ [{ text: "\u2705 I've sent the gift", callbackData: `sent:${deal.dealId}`, style: "success" }]
17857
+ ];
17816
17858
  }
17817
17859
  const remaining = getRemainingTime(deal.expiresAt);
17818
17860
  const text = `\u2705 <b>Deal Accepted</b> #${esc(deal.dealId)}
17819
17861
 
17820
17862
  \u{1F4E4} You send: ${userGives}
17821
17863
  \u{1F4E5} You receive: ${agentGives}
17822
- \u23F1 ${remaining} to complete
17864
+ ${TIMER_EMOJI} ${remaining} to complete
17823
17865
  ${instructions}`;
17824
- return { text, keyboard };
17866
+ return { text, buttons };
17825
17867
  }
17826
17868
  function buildVerifyingMessage(deal) {
17827
17869
  const itemType = deal.userGivesType === "ton" ? "payment" : "gift";
17828
- const text = `\u23F3 <b>Verifying ${itemType}...</b>
17870
+ const text = `${TIMER_EMOJI} <b>Verifying ${itemType}...</b>
17829
17871
 
17830
17872
  Deal #${esc(deal.dealId)}
17831
17873
 
17832
17874
  This usually takes 10-30 seconds.`;
17833
- const keyboard = new InlineKeyboard().text("\u{1F504} Refresh", `refresh:${deal.dealId}`);
17834
- return { text, keyboard };
17875
+ const buttons = [
17876
+ [{ text: "\u{1F504} Refresh", callbackData: `refresh:${deal.dealId}`, style: "primary" }]
17877
+ ];
17878
+ return { text, buttons };
17835
17879
  }
17836
17880
  function buildSendingMessage(deal) {
17837
17881
  const agentGives = formatAsset2(
@@ -17843,8 +17887,7 @@ function buildSendingMessage(deal) {
17843
17887
 
17844
17888
  Deal #${esc(deal.dealId)}
17845
17889
  Sending ${agentGives}...`;
17846
- const keyboard = new InlineKeyboard();
17847
- return { text, keyboard };
17890
+ return { text, buttons: [] };
17848
17891
  }
17849
17892
  function buildCompletedMessage(deal) {
17850
17893
  const userGives = formatAsset2(
@@ -17859,31 +17902,27 @@ function buildCompletedMessage(deal) {
17859
17902
  );
17860
17903
  const user = deal.username ? `@${esc(deal.username)}` : `${deal.userId}`;
17861
17904
  const duration = deal.completedAt ? Math.floor(deal.completedAt - deal.createdAt) : Math.floor(Date.now() / 1e3 - deal.createdAt);
17862
- const text = `\u{1F389} <b>Deal Complete</b> #${esc(deal.dealId)}
17905
+ const text = `\u{1F91D} <b>Deal Complete</b> #${esc(deal.dealId)}
17863
17906
 
17864
17907
  \u{1F464} ${user}
17865
17908
  \u{1F4E4} Sent: ${userGives} \u2713
17866
17909
  \u{1F4E5} Received: ${agentGives} \u2713
17867
- \u23F1 ${duration}s`;
17868
- const keyboard = new InlineKeyboard();
17869
- return { text, keyboard };
17910
+ ${TIMER_EMOJI} ${duration}s`;
17911
+ return { text, buttons: [] };
17870
17912
  }
17871
17913
  function buildDeclinedMessage(deal) {
17872
17914
  const text = `\u274C <b>Deal Declined</b> #${esc(deal.dealId)}`;
17873
- const keyboard = new InlineKeyboard();
17874
- return { text, keyboard };
17915
+ return { text, buttons: [] };
17875
17916
  }
17876
17917
  function buildExpiredMessage(deal) {
17877
- const text = `\u23F0 <b>Deal Expired</b> #${esc(deal.dealId)}`;
17878
- const keyboard = new InlineKeyboard();
17879
- return { text, keyboard };
17918
+ const text = `${TIMER_EMOJI} <b>Deal Expired</b> #${esc(deal.dealId)}`;
17919
+ return { text, buttons: [] };
17880
17920
  }
17881
17921
  function buildFailedMessage(deal, error) {
17882
17922
  const text = `\u274C <b>Deal Failed</b> #${esc(deal.dealId)}
17883
17923
 
17884
17924
  ${esc(error || "Unknown error")}`;
17885
- const keyboard = new InlineKeyboard();
17886
- return { text, keyboard };
17925
+ return { text, buttons: [] };
17887
17926
  }
17888
17927
  function buildNotFoundMessage(dealId) {
17889
17928
  return `\u274C Deal #${esc(dealId)} not found.`;
@@ -17911,6 +17950,255 @@ function buildMessageForState(deal, agentWallet) {
17911
17950
  }
17912
17951
  }
17913
17952
 
17953
+ // src/bot/services/styled-keyboard.ts
17954
+ import { Api as Api54 } from "telegram";
17955
+ import { InlineKeyboard } from "grammy";
17956
+ function toTLMarkup(buttons) {
17957
+ const ApiAny = Api54;
17958
+ return new Api54.ReplyInlineMarkup({
17959
+ rows: buttons.filter((row) => row.length > 0).map(
17960
+ (row) => new Api54.KeyboardButtonRow({
17961
+ buttons: row.map((btn) => {
17962
+ if (btn.copyText) {
17963
+ return new ApiAny.KeyboardButtonCopy({
17964
+ text: btn.text,
17965
+ copyText: btn.copyText
17966
+ });
17967
+ }
17968
+ const style = btn.style ? new ApiAny.KeyboardButtonStyle({
17969
+ bgSuccess: btn.style === "success",
17970
+ bgDanger: btn.style === "danger",
17971
+ bgPrimary: btn.style === "primary"
17972
+ }) : void 0;
17973
+ return new ApiAny.KeyboardButtonCallback({
17974
+ text: btn.text,
17975
+ data: Buffer.from(btn.callbackData),
17976
+ style
17977
+ });
17978
+ })
17979
+ })
17980
+ )
17981
+ });
17982
+ }
17983
+ function toGrammyKeyboard(buttons) {
17984
+ const kb = new InlineKeyboard();
17985
+ for (let i = 0; i < buttons.length; i++) {
17986
+ if (i > 0) kb.row();
17987
+ for (const btn of buttons[i]) {
17988
+ if (btn.copyText) {
17989
+ kb.copyText(btn.text, btn.copyText);
17990
+ } else {
17991
+ kb.text(btn.text, btn.callbackData);
17992
+ }
17993
+ }
17994
+ }
17995
+ return kb;
17996
+ }
17997
+ function hasStyledButtons(buttons) {
17998
+ return buttons.some((row) => row.length > 0);
17999
+ }
18000
+
18001
+ // src/bot/services/html-parser.ts
18002
+ import { Api as Api55 } from "telegram";
18003
+ import bigInt5 from "big-integer";
18004
+ function parseHtml(html) {
18005
+ const entities = [];
18006
+ let text = "";
18007
+ let pos = 0;
18008
+ const stack = [];
18009
+ while (pos < html.length) {
18010
+ if (html[pos] === "<") {
18011
+ const endBracket = html.indexOf(">", pos);
18012
+ if (endBracket === -1) {
18013
+ text += "<";
18014
+ pos++;
18015
+ continue;
18016
+ }
18017
+ const tagStr = html.substring(pos + 1, endBracket);
18018
+ if (tagStr.startsWith("/")) {
18019
+ const tagName = tagStr.substring(1).toLowerCase().trim();
18020
+ for (let i = stack.length - 1; i >= 0; i--) {
18021
+ if (stack[i].tag === tagName) {
18022
+ const open = stack[i];
18023
+ const length = text.length - open.offset;
18024
+ if (length > 0) {
18025
+ switch (tagName) {
18026
+ case "b":
18027
+ case "strong":
18028
+ entities.push(new Api55.MessageEntityBold({ offset: open.offset, length }));
18029
+ break;
18030
+ case "i":
18031
+ case "em":
18032
+ entities.push(new Api55.MessageEntityItalic({ offset: open.offset, length }));
18033
+ break;
18034
+ case "code":
18035
+ entities.push(new Api55.MessageEntityCode({ offset: open.offset, length }));
18036
+ break;
18037
+ case "a":
18038
+ if (open.url) {
18039
+ entities.push(
18040
+ new Api55.MessageEntityTextUrl({
18041
+ offset: open.offset,
18042
+ length,
18043
+ url: open.url
18044
+ })
18045
+ );
18046
+ }
18047
+ break;
18048
+ case "tg-emoji":
18049
+ if (open.emojiId) {
18050
+ entities.push(
18051
+ new Api55.MessageEntityCustomEmoji({
18052
+ offset: open.offset,
18053
+ length,
18054
+ documentId: bigInt5(open.emojiId)
18055
+ })
18056
+ );
18057
+ }
18058
+ break;
18059
+ }
18060
+ }
18061
+ stack.splice(i, 1);
18062
+ break;
18063
+ }
18064
+ }
18065
+ } else {
18066
+ const spaceIdx = tagStr.indexOf(" ");
18067
+ const tagName = (spaceIdx >= 0 ? tagStr.substring(0, spaceIdx) : tagStr).toLowerCase();
18068
+ const attrs = spaceIdx >= 0 ? tagStr.substring(spaceIdx) : "";
18069
+ let url;
18070
+ let emojiId;
18071
+ if (tagName === "a") {
18072
+ const hrefMatch = attrs.match(/href="([^"]+)"/);
18073
+ if (hrefMatch) url = unescapeHtml(hrefMatch[1]);
18074
+ } else if (tagName === "tg-emoji") {
18075
+ const eidMatch = attrs.match(/emoji-id="([^"]+)"/);
18076
+ if (eidMatch) emojiId = eidMatch[1];
18077
+ }
18078
+ stack.push({ tag: tagName, offset: text.length, url, emojiId });
18079
+ }
18080
+ pos = endBracket + 1;
18081
+ } else if (html.substring(pos, pos + 5) === "&amp;") {
18082
+ text += "&";
18083
+ pos += 5;
18084
+ } else if (html.substring(pos, pos + 4) === "&lt;") {
18085
+ text += "<";
18086
+ pos += 4;
18087
+ } else if (html.substring(pos, pos + 4) === "&gt;") {
18088
+ text += ">";
18089
+ pos += 4;
18090
+ } else if (html.substring(pos, pos + 6) === "&quot;") {
18091
+ text += '"';
18092
+ pos += 6;
18093
+ } else {
18094
+ text += html[pos];
18095
+ pos++;
18096
+ }
18097
+ }
18098
+ return { text, entities };
18099
+ }
18100
+ function stripCustomEmoji(html) {
18101
+ return html.replace(/<tg-emoji[^>]*>([^<]*)<\/tg-emoji>/g, "$1");
18102
+ }
18103
+ function unescapeHtml(text) {
18104
+ return text.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"');
18105
+ }
18106
+
18107
+ // src/bot/gramjs-bot.ts
18108
+ import { TelegramClient as TelegramClient2, Api as Api56 } from "telegram";
18109
+ import { StringSession as StringSession2 } from "telegram/sessions/index.js";
18110
+ import { Logger as Logger2, LogLevel as LogLevel2 } from "telegram/extensions/Logger.js";
18111
+ import bigInt6 from "big-integer";
18112
+ function decodeInlineMessageId(encoded) {
18113
+ const buf = Buffer.from(encoded, "base64url");
18114
+ if (buf.length === 20) {
18115
+ return new Api56.InputBotInlineMessageID({
18116
+ dcId: buf.readInt32LE(0),
18117
+ id: bigInt6(buf.readBigInt64LE(4).toString()),
18118
+ accessHash: bigInt6(buf.readBigInt64LE(12).toString())
18119
+ });
18120
+ } else if (buf.length === 24) {
18121
+ return new Api56.InputBotInlineMessageID64({
18122
+ dcId: buf.readInt32LE(0),
18123
+ ownerId: bigInt6(buf.readBigInt64LE(4).toString()),
18124
+ id: buf.readInt32LE(12),
18125
+ accessHash: bigInt6(buf.readBigInt64LE(16).toString())
18126
+ });
18127
+ }
18128
+ throw new Error(`Unknown inline_message_id format (${buf.length} bytes)`);
18129
+ }
18130
+ var GramJSBotClient = class {
18131
+ client;
18132
+ connected = false;
18133
+ constructor(apiId, apiHash) {
18134
+ const logger = new Logger2(LogLevel2.NONE);
18135
+ this.client = new TelegramClient2(new StringSession2(""), apiId, apiHash, {
18136
+ connectionRetries: 3,
18137
+ retryDelay: 1e3,
18138
+ autoReconnect: true,
18139
+ baseLogger: logger
18140
+ });
18141
+ }
18142
+ /**
18143
+ * Connect and authenticate as bot via MTProto
18144
+ */
18145
+ async connect(botToken) {
18146
+ try {
18147
+ await this.client.start({ botAuthToken: botToken });
18148
+ this.connected = true;
18149
+ console.log("\u{1F3A8} [Bot] Styled buttons enabled (MTProto)");
18150
+ } catch (error) {
18151
+ console.error("\u274C [GramJS Bot] Connection failed:", error);
18152
+ throw error;
18153
+ }
18154
+ }
18155
+ isConnected() {
18156
+ return this.connected;
18157
+ }
18158
+ /**
18159
+ * Answer an inline query with styled buttons via MTProto
18160
+ */
18161
+ async answerInlineQuery(params) {
18162
+ if (!this.connected) throw new Error("GramJS bot not connected");
18163
+ await this.client.invoke(
18164
+ new Api56.messages.SetInlineBotResults({
18165
+ queryId: bigInt6(params.queryId),
18166
+ results: params.results,
18167
+ cacheTime: params.cacheTime ?? 0
18168
+ })
18169
+ );
18170
+ }
18171
+ /**
18172
+ * Edit an inline message with styled/copy buttons via MTProto.
18173
+ * Accepts the Bot API inline_message_id string directly (decodes internally).
18174
+ */
18175
+ async editInlineMessageByStringId(params) {
18176
+ if (!this.connected) throw new Error("GramJS bot not connected");
18177
+ const id = decodeInlineMessageId(params.inlineMessageId);
18178
+ const dcId = id.dcId;
18179
+ await this.client.invoke(
18180
+ new Api56.messages.EditInlineBotMessage({
18181
+ id,
18182
+ message: params.text,
18183
+ entities: params.entities,
18184
+ replyMarkup: params.replyMarkup,
18185
+ noWebpage: true
18186
+ }),
18187
+ dcId
18188
+ );
18189
+ }
18190
+ async disconnect() {
18191
+ if (!this.connected) return;
18192
+ try {
18193
+ await this.client.disconnect();
18194
+ this.connected = false;
18195
+ console.log("\u{1F6D1} [GramJS Bot] Disconnected");
18196
+ } catch (error) {
18197
+ console.error("\u274C [GramJS Bot] Disconnect error:", error);
18198
+ }
18199
+ }
18200
+ };
18201
+
17914
18202
  // src/bot/services/verification-poller.ts
17915
18203
  var VerificationPoller = class {
17916
18204
  db;
@@ -17935,10 +18223,10 @@ var VerificationPoller = class {
17935
18223
  return;
17936
18224
  }
17937
18225
  console.log(`\u{1F504} [Poller] Started (interval: ${this.config.pollIntervalMs}ms)`);
17938
- this.intervalId = setInterval(async () => {
17939
- await this.poll();
18226
+ this.intervalId = setInterval(() => {
18227
+ this.poll().catch((err) => console.error("\u274C [Poller] Unhandled poll error:", err));
17940
18228
  }, this.config.pollIntervalMs);
17941
- this.poll();
18229
+ this.poll().catch((err) => console.error("\u274C [Poller] Initial poll error:", err));
17942
18230
  }
17943
18231
  /**
17944
18232
  * Stop polling
@@ -18091,22 +18379,22 @@ var VerificationPoller = class {
18091
18379
  ).run(giftMsgId, deal.dealId);
18092
18380
  }
18093
18381
  if (deal.inlineMessageId) {
18094
- const { text, keyboard } = buildSendingMessage(deal);
18095
- await this.bot.editMessageByInlineId(deal.inlineMessageId, text, keyboard);
18382
+ const { text, buttons } = buildSendingMessage(deal);
18383
+ await this.bot.editMessageByInlineId(deal.inlineMessageId, text, buttons);
18096
18384
  }
18097
18385
  const result = await executeDeal(deal.dealId, this.db, this.bridge);
18098
18386
  if (result.success) {
18099
18387
  updateUserStats(this.db, deal.userId, deal.username, deal, true);
18100
18388
  const completedDeal = { ...deal, status: "completed" };
18101
18389
  if (deal.inlineMessageId) {
18102
- const { text, keyboard } = buildCompletedMessage(completedDeal);
18103
- await this.bot.editMessageByInlineId(deal.inlineMessageId, text, keyboard);
18390
+ const { text, buttons } = buildCompletedMessage(completedDeal);
18391
+ await this.bot.editMessageByInlineId(deal.inlineMessageId, text, buttons);
18104
18392
  }
18105
18393
  console.log(`\u{1F389} [Poller] Deal ${deal.dealId} completed successfully!`);
18106
18394
  } else {
18107
18395
  if (deal.inlineMessageId) {
18108
- const { text, keyboard } = buildFailedMessage(deal, result.error);
18109
- await this.bot.editMessageByInlineId(deal.inlineMessageId, text, keyboard);
18396
+ const { text, buttons } = buildFailedMessage(deal, result.error);
18397
+ await this.bot.editMessageByInlineId(deal.inlineMessageId, text, buttons);
18110
18398
  }
18111
18399
  console.error(`\u274C [Poller] Deal ${deal.dealId} execution failed:`, result.error);
18112
18400
  }
@@ -18122,11 +18410,11 @@ var VerificationPoller = class {
18122
18410
  WHERE id = ?`
18123
18411
  ).run(deal.dealId);
18124
18412
  if (deal.inlineMessageId) {
18125
- const { text, keyboard } = buildFailedMessage(
18413
+ const { text, buttons } = buildFailedMessage(
18126
18414
  deal,
18127
18415
  "Payment not detected after 60 seconds. Contact support if you have sent it."
18128
18416
  );
18129
- await this.bot.editMessageByInlineId(deal.inlineMessageId, text, keyboard);
18417
+ await this.bot.editMessageByInlineId(deal.inlineMessageId, text, buttons);
18130
18418
  }
18131
18419
  await this.bridge.sendMessage({
18132
18420
  chatId: deal.chatId,
@@ -18145,21 +18433,20 @@ var DealBot = class {
18145
18433
  bot;
18146
18434
  db;
18147
18435
  config;
18436
+ gramjsBot = null;
18148
18437
  constructor(config, db) {
18149
18438
  this.config = config;
18150
18439
  this.db = db;
18151
18440
  this.bot = new Bot(config.token);
18441
+ if (config.apiId && config.apiHash) {
18442
+ this.gramjsBot = new GramJSBotClient(config.apiId, config.apiHash);
18443
+ }
18152
18444
  this.setupHandlers();
18153
18445
  }
18154
- /**
18155
- * Check if keyboard has buttons
18156
- */
18157
- hasButtons(keyboard) {
18158
- return keyboard.inline_keyboard?.length > 0;
18159
- }
18160
18446
  setupHandlers() {
18161
18447
  this.bot.on("inline_query", async (ctx) => {
18162
18448
  const query = ctx.inlineQuery.query.trim();
18449
+ const queryId = ctx.inlineQuery.id;
18163
18450
  const userId = ctx.from.id;
18164
18451
  console.log(`\u{1F50D} [Bot] Inline query from ${userId}: "${query}"`);
18165
18452
  const dealId = query;
@@ -18204,7 +18491,16 @@ var DealBot = class {
18204
18491
  deal.status = "expired";
18205
18492
  }
18206
18493
  const agentWallet = getWalletAddress() || "";
18207
- const { text, keyboard } = buildMessageForState(deal, agentWallet);
18494
+ const { text, buttons } = buildMessageForState(deal, agentWallet);
18495
+ if (this.gramjsBot?.isConnected() && hasStyledButtons(buttons)) {
18496
+ try {
18497
+ await this.answerInlineQueryStyled(queryId, dealId, deal, text, buttons);
18498
+ return;
18499
+ } catch (error) {
18500
+ console.warn("\u26A0\uFE0F [Bot] GramJS styled answer failed, falling back to Grammy:", error);
18501
+ }
18502
+ }
18503
+ const keyboard = toGrammyKeyboard(buttons);
18208
18504
  await ctx.answerInlineQuery(
18209
18505
  [
18210
18506
  {
@@ -18213,11 +18509,11 @@ var DealBot = class {
18213
18509
  title: `\u{1F4CB} Deal #${dealId}`,
18214
18510
  description: this.formatShortDescription(deal),
18215
18511
  input_message_content: {
18216
- message_text: text,
18512
+ message_text: stripCustomEmoji(text),
18217
18513
  parse_mode: "HTML",
18218
18514
  link_preview_options: { is_disabled: true }
18219
18515
  },
18220
- reply_markup: this.hasButtons(keyboard) ? keyboard : void 0
18516
+ reply_markup: hasStyledButtons(buttons) ? keyboard : void 0
18221
18517
  }
18222
18518
  ],
18223
18519
  { cache_time: 0 }
@@ -18227,8 +18523,39 @@ var DealBot = class {
18227
18523
  const resultId = ctx.chosenInlineResult.result_id;
18228
18524
  const inlineMessageId = ctx.chosenInlineResult.inline_message_id;
18229
18525
  if (inlineMessageId && resultId !== "help" && resultId !== "not_found" && resultId !== "wrong_user") {
18230
- console.log(`\u{1F4DD} [Bot] Storing inline message ID for deal ${resultId}: ${inlineMessageId}`);
18231
18526
  setInlineMessageId(this.db, resultId, inlineMessageId);
18527
+ const deal = getDeal(this.db, resultId);
18528
+ if (deal) {
18529
+ const agentWallet = getWalletAddress() || "";
18530
+ const { text, buttons } = buildMessageForState(deal, agentWallet);
18531
+ let edited = false;
18532
+ if (this.gramjsBot?.isConnected()) {
18533
+ try {
18534
+ await this.editViaGramJS(inlineMessageId, text, buttons);
18535
+ edited = true;
18536
+ } catch (error) {
18537
+ console.warn(
18538
+ "\u26A0\uFE0F [Bot] chosen_inline_result GramJS edit failed:",
18539
+ error?.errorMessage || error
18540
+ );
18541
+ }
18542
+ }
18543
+ if (!edited) {
18544
+ try {
18545
+ const keyboard = hasStyledButtons(buttons) ? toGrammyKeyboard(buttons) : void 0;
18546
+ await this.bot.api.editMessageTextInline(inlineMessageId, stripCustomEmoji(text), {
18547
+ parse_mode: "HTML",
18548
+ link_preview_options: { is_disabled: true },
18549
+ reply_markup: keyboard
18550
+ });
18551
+ } catch (error) {
18552
+ console.error(
18553
+ "\u274C [Bot] chosen_inline_result Grammy fallback failed:",
18554
+ error?.description || error
18555
+ );
18556
+ }
18557
+ }
18558
+ }
18232
18559
  }
18233
18560
  });
18234
18561
  this.bot.on("callback_query:data", async (ctx) => {
@@ -18258,8 +18585,8 @@ var DealBot = class {
18258
18585
  }
18259
18586
  if (isDealExpired(deal) && ["proposed", "accepted"].includes(deal.status)) {
18260
18587
  expireDeal(this.db, dealId);
18261
- const { text, keyboard } = buildExpiredMessage(deal);
18262
- await this.editInlineMessage(ctx, text, keyboard);
18588
+ const { text, buttons } = buildExpiredMessage(deal);
18589
+ await this.editInlineMessage(ctx, text, buttons);
18263
18590
  await ctx.answerCallbackQuery({ text: "Deal expired!" });
18264
18591
  return;
18265
18592
  }
@@ -18288,6 +18615,35 @@ var DealBot = class {
18288
18615
  console.error("\u274C [Bot] Error:", err);
18289
18616
  });
18290
18617
  }
18618
+ /**
18619
+ * Answer inline query via GramJS MTProto with styled buttons.
18620
+ * Sends full deal content (custom emojis stripped since SetInlineBotResults drops them).
18621
+ * chosen_inline_result then edits to upgrade to custom emojis.
18622
+ */
18623
+ async answerInlineQueryStyled(queryId, dealId, deal, htmlText, buttons) {
18624
+ if (!this.gramjsBot) throw new Error("GramJS bot not available");
18625
+ const strippedHtml = stripCustomEmoji(htmlText);
18626
+ const { text: plainText, entities } = parseHtml(strippedHtml);
18627
+ const markup = hasStyledButtons(buttons) ? toTLMarkup(buttons) : void 0;
18628
+ await this.gramjsBot.answerInlineQuery({
18629
+ queryId,
18630
+ results: [
18631
+ new Api57.InputBotInlineResult({
18632
+ id: dealId,
18633
+ type: "article",
18634
+ title: `\u{1F4CB} Deal #${dealId}`,
18635
+ description: this.formatShortDescription(deal),
18636
+ sendMessage: new Api57.InputBotInlineMessageText({
18637
+ message: plainText,
18638
+ entities: entities.length > 0 ? entities : void 0,
18639
+ noWebpage: true,
18640
+ replyMarkup: markup
18641
+ })
18642
+ })
18643
+ ],
18644
+ cacheTime: 0
18645
+ });
18646
+ }
18291
18647
  async handleAccept(ctx, deal) {
18292
18648
  if (deal.status !== "proposed") {
18293
18649
  await ctx.answerCallbackQuery({ text: "Already processed" });
@@ -18295,10 +18651,10 @@ var DealBot = class {
18295
18651
  }
18296
18652
  acceptDeal(this.db, deal.dealId);
18297
18653
  deal.status = "accepted";
18298
- deal.expiresAt = Math.floor(Date.now() / 1e3) + 300;
18654
+ deal.expiresAt = Math.floor(Date.now() / 1e3) + DEAL_VERIFICATION_WINDOW_SECONDS;
18299
18655
  const agentWallet = getWalletAddress() || "";
18300
- const { text, keyboard } = buildAcceptedMessage(deal, agentWallet);
18301
- await this.editInlineMessage(ctx, text, keyboard);
18656
+ const { text, buttons } = buildAcceptedMessage(deal, agentWallet);
18657
+ await this.editInlineMessage(ctx, text, buttons);
18302
18658
  await ctx.answerCallbackQuery({ text: "\u2705 Deal accepted!" });
18303
18659
  console.log(`\u2705 [Bot] Deal ${deal.dealId} accepted by ${deal.userId}`);
18304
18660
  }
@@ -18309,8 +18665,8 @@ var DealBot = class {
18309
18665
  }
18310
18666
  declineDeal(this.db, deal.dealId);
18311
18667
  deal.status = "declined";
18312
- const { text, keyboard } = buildDeclinedMessage(deal);
18313
- await this.editInlineMessage(ctx, text, keyboard);
18668
+ const { text, buttons } = buildDeclinedMessage(deal);
18669
+ await this.editInlineMessage(ctx, text, buttons);
18314
18670
  await ctx.answerCallbackQuery({ text: "\u274C Deal declined" });
18315
18671
  console.log(`\u274C [Bot] Deal ${deal.dealId} declined by ${deal.userId}`);
18316
18672
  }
@@ -18321,8 +18677,8 @@ var DealBot = class {
18321
18677
  }
18322
18678
  claimPayment(this.db, deal.dealId);
18323
18679
  deal.status = "payment_claimed";
18324
- const { text, keyboard } = buildVerifyingMessage(deal);
18325
- await this.editInlineMessage(ctx, text, keyboard);
18680
+ const { text, buttons } = buildVerifyingMessage(deal);
18681
+ await this.editInlineMessage(ctx, text, buttons);
18326
18682
  await ctx.answerCallbackQuery({ text: "\u23F3 Verifying..." });
18327
18683
  console.log(`\u{1F4E4} [Bot] Deal ${deal.dealId} payment claimed by ${deal.userId}`);
18328
18684
  }
@@ -18346,38 +18702,81 @@ var DealBot = class {
18346
18702
  return;
18347
18703
  }
18348
18704
  const agentWallet = getWalletAddress() || "";
18349
- const { text, keyboard } = buildMessageForState(freshDeal, agentWallet);
18350
- await this.editInlineMessage(ctx, text, keyboard);
18705
+ const { text, buttons } = buildMessageForState(freshDeal, agentWallet);
18706
+ await this.editInlineMessage(ctx, text, buttons);
18351
18707
  await ctx.answerCallbackQuery({ text: "\u{1F504} Refreshed" });
18352
18708
  }
18353
- async editInlineMessage(ctx, text, keyboard) {
18354
- try {
18355
- if (ctx.callbackQuery?.inline_message_id) {
18356
- await ctx.editMessageText(text, {
18357
- parse_mode: "HTML",
18358
- link_preview_options: { is_disabled: true },
18359
- reply_markup: this.hasButtons(keyboard) ? keyboard : void 0
18360
- });
18709
+ /**
18710
+ * Edit inline message: try GramJS MTProto first (styled + copy buttons), fallback to Grammy
18711
+ */
18712
+ async editInlineMessage(ctx, text, buttons) {
18713
+ const inlineMsgId = ctx.callbackQuery?.inline_message_id;
18714
+ if (!inlineMsgId) return;
18715
+ if (this.gramjsBot?.isConnected()) {
18716
+ try {
18717
+ await this.editViaGramJS(inlineMsgId, text, buttons);
18718
+ return;
18719
+ } catch (error) {
18720
+ if (error?.errorMessage === "MESSAGE_NOT_MODIFIED") return;
18721
+ console.warn(
18722
+ "\u26A0\uFE0F [Bot] GramJS edit failed, falling back to Grammy:",
18723
+ error?.errorMessage || error
18724
+ );
18361
18725
  }
18726
+ }
18727
+ try {
18728
+ const keyboard = hasStyledButtons(buttons) ? toGrammyKeyboard(buttons) : void 0;
18729
+ await ctx.editMessageText(stripCustomEmoji(text), {
18730
+ parse_mode: "HTML",
18731
+ link_preview_options: { is_disabled: true },
18732
+ reply_markup: keyboard
18733
+ });
18362
18734
  } catch (error) {
18363
18735
  if (error?.description?.includes("message is not modified")) return;
18364
18736
  console.error("\u274C [Bot] Failed to edit inline message:", error);
18365
18737
  }
18366
18738
  }
18367
18739
  /**
18368
- * Edit a message by inline_message_id (for external updates)
18740
+ * Edit a message by inline_message_id (for external updates like VerificationPoller)
18369
18741
  */
18370
- async editMessageByInlineId(inlineMessageId, text, keyboard) {
18742
+ async editMessageByInlineId(inlineMessageId, text, buttons) {
18743
+ if (this.gramjsBot?.isConnected() && buttons) {
18744
+ try {
18745
+ await this.editViaGramJS(inlineMessageId, text, buttons);
18746
+ return;
18747
+ } catch (error) {
18748
+ if (error?.errorMessage === "MESSAGE_NOT_MODIFIED") return;
18749
+ console.warn(
18750
+ "\u26A0\uFE0F [Bot] GramJS edit failed, falling back to Grammy:",
18751
+ error?.errorMessage || error
18752
+ );
18753
+ }
18754
+ }
18371
18755
  try {
18372
- await this.bot.api.editMessageTextInline(inlineMessageId, text, {
18756
+ const keyboard = buttons && hasStyledButtons(buttons) ? toGrammyKeyboard(buttons) : void 0;
18757
+ await this.bot.api.editMessageTextInline(inlineMessageId, stripCustomEmoji(text), {
18373
18758
  parse_mode: "HTML",
18374
18759
  link_preview_options: { is_disabled: true },
18375
- reply_markup: keyboard && this.hasButtons(keyboard) ? keyboard : void 0
18760
+ reply_markup: keyboard
18376
18761
  });
18377
18762
  } catch (error) {
18378
18763
  console.error("\u274C [Bot] Failed to edit message by inline ID:", error);
18379
18764
  }
18380
18765
  }
18766
+ /**
18767
+ * Edit inline message via GramJS MTProto (styled + copy buttons)
18768
+ */
18769
+ async editViaGramJS(inlineMessageId, htmlText, buttons) {
18770
+ if (!this.gramjsBot) throw new Error("GramJS bot not available");
18771
+ const { text: plainText, entities } = parseHtml(htmlText);
18772
+ const markup = hasStyledButtons(buttons) ? toTLMarkup(buttons) : void 0;
18773
+ await this.gramjsBot.editInlineMessageByStringId({
18774
+ inlineMessageId,
18775
+ text: plainText,
18776
+ entities: entities.length > 0 ? entities : void 0,
18777
+ replyMarkup: markup
18778
+ });
18779
+ }
18381
18780
  formatShortDescription(deal) {
18382
18781
  const userGives = deal.userGivesType === "ton" ? `${deal.userGivesTonAmount} TON` : deal.userGivesGiftSlug || "Gift";
18383
18782
  const agentGives = deal.agentGivesType === "ton" ? `${deal.agentGivesTonAmount} TON` : deal.agentGivesGiftSlug || "Gift";
@@ -18388,9 +18787,19 @@ var DealBot = class {
18388
18787
  */
18389
18788
  async start() {
18390
18789
  console.log(`\u{1F916} [Bot] Starting @${this.config.username}...`);
18790
+ if (this.gramjsBot) {
18791
+ try {
18792
+ await this.gramjsBot.connect(this.config.token);
18793
+ } catch {
18794
+ console.warn("\u26A0\uFE0F [Bot] GramJS MTProto connection failed, buttons will be unstyled");
18795
+ this.gramjsBot = null;
18796
+ }
18797
+ }
18391
18798
  await this.bot.init();
18392
18799
  this.bot.start({
18393
18800
  onStart: () => console.log(`\u{1F916} [Bot] @${this.config.username} polling started`)
18801
+ }).catch((err) => {
18802
+ console.error(`\u274C [Bot] Polling error:`, err);
18394
18803
  });
18395
18804
  }
18396
18805
  /**
@@ -18399,6 +18808,9 @@ var DealBot = class {
18399
18808
  async stop() {
18400
18809
  console.log(`\u{1F6D1} [Bot] Stopping @${this.config.username}...`);
18401
18810
  await this.bot.stop();
18811
+ if (this.gramjsBot) {
18812
+ await this.gramjsBot.disconnect();
18813
+ }
18402
18814
  }
18403
18815
  /**
18404
18816
  * Get bot instance for external access
@@ -18430,143 +18842,7 @@ var TonnetApp = class {
18430
18842
  initDealsConfig(this.config.deals);
18431
18843
  const soul = loadSoul();
18432
18844
  this.toolRegistry = new ToolRegistry();
18433
- this.toolRegistry.register(telegramSendMessageTool, telegramSendMessageExecutor);
18434
- this.toolRegistry.register(telegramQuoteReplyTool, telegramQuoteReplyExecutor);
18435
- this.toolRegistry.register(telegramGetRepliesTool, telegramGetRepliesExecutor);
18436
- this.toolRegistry.register(telegramEditMessageTool, telegramEditMessageExecutor);
18437
- this.toolRegistry.register(telegramScheduleMessageTool, telegramScheduleMessageExecutor);
18438
- this.toolRegistry.register(
18439
- telegramCreateScheduledTaskTool,
18440
- telegramCreateScheduledTaskExecutor
18441
- );
18442
- this.toolRegistry.register(telegramSearchMessagesTool, telegramSearchMessagesExecutor);
18443
- this.toolRegistry.register(telegramPinMessageTool, telegramPinMessageExecutor);
18444
- this.toolRegistry.register(telegramUnpinMessageTool, telegramUnpinMessageExecutor);
18445
- this.toolRegistry.register(telegramReactTool, telegramReactExecutor);
18446
- this.toolRegistry.register(telegramSendDiceTool, telegramSendDiceExecutor);
18447
- this.toolRegistry.register(telegramForwardMessageTool, telegramForwardMessageExecutor);
18448
- this.toolRegistry.register(telegramSendPhotoTool, telegramSendPhotoExecutor);
18449
- this.toolRegistry.register(telegramSendVoiceTool, telegramSendVoiceExecutor);
18450
- this.toolRegistry.register(telegramSendStickerTool, telegramSendStickerExecutor);
18451
- this.toolRegistry.register(telegramSendGifTool, telegramSendGifExecutor);
18452
- this.toolRegistry.register(telegramCreatePollTool, telegramCreatePollExecutor);
18453
- this.toolRegistry.register(telegramCreateQuizTool, telegramCreateQuizExecutor);
18454
- this.toolRegistry.register(telegramReplyKeyboardTool, telegramReplyKeyboardExecutor);
18455
- this.toolRegistry.register(telegramSearchStickersTool, telegramSearchStickersExecutor);
18456
- this.toolRegistry.register(telegramGetMyStickersTool, telegramGetMyStickersExecutor);
18457
- this.toolRegistry.register(telegramSearchGifsTool, telegramSearchGifsExecutor);
18458
- this.toolRegistry.register(telegramAddStickerSetTool, telegramAddStickerSetExecutor);
18459
- this.toolRegistry.register(telegramGetHistoryTool, telegramGetHistoryExecutor);
18460
- this.toolRegistry.register(telegramGetDialogsTool, telegramGetDialogsExecutor);
18461
- this.toolRegistry.register(telegramMarkAsReadTool, telegramMarkAsReadExecutor);
18462
- this.toolRegistry.register(telegramGetChatInfoTool, telegramGetChatInfoExecutor);
18463
- this.toolRegistry.register(telegramJoinChannelTool, telegramJoinChannelExecutor);
18464
- this.toolRegistry.register(telegramLeaveChannelTool, telegramLeaveChannelExecutor);
18465
- this.toolRegistry.register(telegramGetMeTool, telegramGetMeExecutor);
18466
- this.toolRegistry.register(telegramGetParticipantsTool, telegramGetParticipantsExecutor);
18467
- this.toolRegistry.register(telegramKickUserTool, telegramKickUserExecutor);
18468
- this.toolRegistry.register(telegramBanUserTool, telegramBanUserExecutor);
18469
- this.toolRegistry.register(telegramUnbanUserTool, telegramUnbanUserExecutor);
18470
- this.toolRegistry.register(telegramCreateGroupTool, telegramCreateGroupExecutor);
18471
- this.toolRegistry.register(telegramSetChatPhotoTool, telegramSetChatPhotoExecutor);
18472
- this.toolRegistry.register(telegramBlockUserTool, telegramBlockUserExecutor);
18473
- this.toolRegistry.register(telegramGetBlockedTool, telegramGetBlockedExecutor);
18474
- this.toolRegistry.register(telegramGetCommonChatsTool, telegramGetCommonChatsExecutor);
18475
- this.toolRegistry.register(telegramSendStoryTool, telegramSendStoryExecutor);
18476
- this.toolRegistry.register(telegramGetFoldersTool, telegramGetFoldersExecutor);
18477
- this.toolRegistry.register(telegramCreateFolderTool, telegramCreateFolderExecutor);
18478
- this.toolRegistry.register(telegramAddChatToFolderTool, telegramAddChatToFolderExecutor);
18479
- this.toolRegistry.register(telegramCreateChannelTool, telegramCreateChannelExecutor);
18480
- this.toolRegistry.register(telegramUpdateProfileTool, telegramUpdateProfileExecutor);
18481
- this.toolRegistry.register(telegramSetBioTool, telegramSetBioExecutor);
18482
- this.toolRegistry.register(telegramSetUsernameTool, telegramSetUsernameExecutor);
18483
- this.toolRegistry.register(telegramDeleteMessageTool, telegramDeleteMessageExecutor);
18484
- this.toolRegistry.register(telegramDownloadMediaTool, telegramDownloadMediaExecutor);
18485
- this.toolRegistry.register(visionAnalyzeTool, visionAnalyzeExecutor);
18486
- this.toolRegistry.register(telegramGetStarsBalanceTool, telegramGetStarsBalanceExecutor);
18487
- this.toolRegistry.register(
18488
- telegramGetStarsTransactionsTool,
18489
- telegramGetStarsTransactionsExecutor
18490
- );
18491
- this.toolRegistry.register(telegramGetAvailableGiftsTool, telegramGetAvailableGiftsExecutor);
18492
- this.toolRegistry.register(telegramSendGiftTool, telegramSendGiftExecutor);
18493
- this.toolRegistry.register(telegramGetMyGiftsTool, telegramGetMyGiftsExecutor);
18494
- this.toolRegistry.register(
18495
- telegramTransferCollectibleTool,
18496
- telegramTransferCollectibleExecutor
18497
- );
18498
- this.toolRegistry.register(
18499
- telegramSetCollectiblePriceTool,
18500
- telegramSetCollectiblePriceExecutor
18501
- );
18502
- this.toolRegistry.register(telegramGetResaleGiftsTool, telegramGetResaleGiftsExecutor);
18503
- this.toolRegistry.register(telegramBuyResaleGiftTool, telegramBuyResaleGiftExecutor);
18504
- this.toolRegistry.register(telegramSetGiftStatusTool, telegramSetGiftStatusExecutor);
18505
- this.toolRegistry.register(memoryWriteTool, memoryWriteExecutor);
18506
- this.toolRegistry.register(memoryReadTool, memoryReadExecutor);
18507
- this.toolRegistry.register(telegramGetUserInfoTool, telegramGetUserInfoExecutor);
18508
- this.toolRegistry.register(telegramCheckUsernameTool, telegramCheckUsernameExecutor);
18509
- this.toolRegistry.register(telegramEditChannelInfoTool, telegramEditChannelInfoExecutor);
18510
- this.toolRegistry.register(telegramInviteToChannelTool, telegramInviteToChannelExecutor);
18511
- this.toolRegistry.register(marketGetFloorTool, marketGetFloorExecutor);
18512
- this.toolRegistry.register(marketSearchTool, marketSearchExecutor);
18513
- this.toolRegistry.register(marketCheapestTool, marketCheapestExecutor);
18514
- this.toolRegistry.register(marketPriceHistoryTool, marketPriceHistoryExecutor);
18515
- this.toolRegistry.register(tonGetAddressTool, tonGetAddressExecutor);
18516
- this.toolRegistry.register(tonGetBalanceTool, tonGetBalanceExecutor);
18517
- this.toolRegistry.register(tonPriceTool, tonPriceExecutor);
18518
- this.toolRegistry.register(tonSendTool, tonSendExecutor);
18519
- this.toolRegistry.register(tonGetTransactionsTool, tonGetTransactionsExecutor);
18520
- this.toolRegistry.register(tonMyTransactionsTool, tonMyTransactionsExecutor);
18521
- this.toolRegistry.register(jettonBalancesTool, jettonBalancesExecutor);
18522
- this.toolRegistry.register(jettonSwapTool, jettonSwapExecutor);
18523
- this.toolRegistry.register(jettonSendTool, jettonSendExecutor);
18524
- this.toolRegistry.register(jettonInfoTool, jettonInfoExecutor);
18525
- this.toolRegistry.register(jettonPriceTool, jettonPriceExecutor);
18526
- this.toolRegistry.register(jettonSearchTool, jettonSearchExecutor);
18527
- this.toolRegistry.register(jettonQuoteTool, jettonQuoteExecutor);
18528
- this.toolRegistry.register(jettonHoldersTool, jettonHoldersExecutor);
18529
- this.toolRegistry.register(jettonHistoryTool, jettonHistoryExecutor);
18530
- this.toolRegistry.register(jettonTrendingTool, jettonTrendingExecutor);
18531
- this.toolRegistry.register(jettonPoolsTool, jettonPoolsExecutor);
18532
- this.toolRegistry.register(dnsCheckTool, dnsCheckExecutor);
18533
- this.toolRegistry.register(dnsAuctionsTool, dnsAuctionsExecutor);
18534
- this.toolRegistry.register(dnsResolveTool, dnsResolveExecutor);
18535
- this.toolRegistry.register(dnsStartAuctionTool, dnsStartAuctionExecutor);
18536
- this.toolRegistry.register(dnsBidTool, dnsBidExecutor);
18537
- this.toolRegistry.register(dnsLinkTool, dnsLinkExecutor);
18538
- this.toolRegistry.register(dnsUnlinkTool, dnsUnlinkExecutor);
18539
- this.toolRegistry.register(dedustQuoteTool, dedustQuoteExecutor);
18540
- this.toolRegistry.register(dedustSwapTool, dedustSwapExecutor);
18541
- this.toolRegistry.register(dedustPoolsTool, dedustPoolsExecutor);
18542
- this.toolRegistry.register(dexQuoteTool, dexQuoteExecutor);
18543
- this.toolRegistry.register(dexSwapTool, dexSwapExecutor);
18544
- this.toolRegistry.register(journalLogTool, journalLogExecutor);
18545
- this.toolRegistry.register(journalQueryTool, journalQueryExecutor);
18546
- this.toolRegistry.register(journalUpdateTool, journalUpdateExecutor);
18547
- this.toolRegistry.register(workspaceListTool, workspaceListExecutor);
18548
- this.toolRegistry.register(workspaceReadTool, workspaceReadExecutor);
18549
- this.toolRegistry.register(workspaceWriteTool, workspaceWriteExecutor);
18550
- this.toolRegistry.register(workspaceDeleteTool, workspaceDeleteExecutor);
18551
- this.toolRegistry.register(workspaceInfoTool, workspaceInfoExecutor);
18552
- this.toolRegistry.register(workspaceRenameTool, workspaceRenameExecutor);
18553
- if (this.config.casino.enabled) {
18554
- this.toolRegistry.register(casinoBalanceTool, casinoBalanceExecutor);
18555
- this.toolRegistry.register(casinoSpinTool, casinoSpinExecutor);
18556
- this.toolRegistry.register(casinoDiceTool, casinoDiceExecutor);
18557
- this.toolRegistry.register(casinoPayoutTool, casinoPayoutExecutor);
18558
- this.toolRegistry.register(casinoLeaderboardTool, casinoLeaderboardExecutor);
18559
- this.toolRegistry.register(casinoMyStatsTool, casinoMyStatsExecutor);
18560
- this.toolRegistry.register(casinoJackpotInfoTool, casinoJackpotInfoExecutor);
18561
- this.toolRegistry.register(casinoAwardJackpotTool, casinoAwardJackpotExecutor);
18562
- }
18563
- if (this.config.deals.enabled) {
18564
- this.toolRegistry.register(dealProposeTool, dealProposeExecutor);
18565
- this.toolRegistry.register(dealVerifyPaymentTool, dealVerifyPaymentExecutor);
18566
- this.toolRegistry.register(dealStatusTool, dealStatusExecutor);
18567
- this.toolRegistry.register(dealListTool, dealListExecutor);
18568
- this.toolRegistry.register(dealCancelTool, dealCancelExecutor);
18569
- }
18845
+ registerAllTools(this.toolRegistry, this.config);
18570
18846
  this.toolCount = this.toolRegistry.count;
18571
18847
  this.agent = new AgentRuntime(this.config, soul, this.toolRegistry);
18572
18848
  const TELEGRAM_CONNECTION_RETRIES = 5;
@@ -18634,7 +18910,7 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
18634
18910
  `\u26A0\uFE0F Tool count (${this.toolCount}) exceeds ${providerMeta.displayName} limit (${providerMeta.toolLimit})`
18635
18911
  );
18636
18912
  }
18637
- const { migrateSessionsToDb } = await import("./migrate-25RH22HJ.js");
18913
+ const { migrateSessionsToDb } = await import("./migrate-JPXMIIPI.js");
18638
18914
  migrateSessionsToDb();
18639
18915
  const memory = initializeMemory({
18640
18916
  database: {
@@ -18673,7 +18949,12 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
18673
18949
  if (botToken && botToken !== "YOUR_BOT_TOKEN_FROM_BOTFATHER") {
18674
18950
  try {
18675
18951
  this.dealBot = new DealBot(
18676
- { token: botToken, username: botUsername || "deals_bot" },
18952
+ {
18953
+ token: botToken,
18954
+ username: botUsername || "deals_bot",
18955
+ apiId: this.config.telegram.api_id,
18956
+ apiHash: this.config.telegram.api_hash
18957
+ },
18677
18958
  db.getDb()
18678
18959
  );
18679
18960
  await this.dealBot.start();
@@ -18788,8 +19069,8 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
18788
19069
  }
18789
19070
  const taskId = match[1];
18790
19071
  const { getTaskStore } = await import("./tasks-NUFMZNV5.js");
18791
- const { executeScheduledTask } = await import("./task-executor-ZMXWLMI7.js");
18792
- const { getDatabase: getDatabase2 } = await import("./memory-O5NYYWF3.js");
19072
+ const { executeScheduledTask } = await import("./task-executor-L6DTJANH.js");
19073
+ const { getDatabase: getDatabase2 } = await import("./memory-WSP5MEER.js");
18793
19074
  const db = getDatabase2().getDb();
18794
19075
  const taskStore = getTaskStore(db);
18795
19076
  const task = taskStore.getTask(taskId);
@@ -18855,7 +19136,7 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
18855
19136
  taskStore.completeTask(taskId, response.content);
18856
19137
  console.log(`\u2705 Executed scheduled task ${taskId}: ${task.description}`);
18857
19138
  if (!this.dependencyResolver) {
18858
- const { TaskDependencyResolver } = await import("./task-dependency-resolver-5I62EU67.js");
19139
+ const { TaskDependencyResolver } = await import("./task-dependency-resolver-KRQRZKAD.js");
18859
19140
  this.dependencyResolver = new TaskDependencyResolver(taskStore, this.bridge);
18860
19141
  }
18861
19142
  await this.dependencyResolver.onTaskComplete(taskId);
@@ -18863,8 +19144,8 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
18863
19144
  console.error("Error handling scheduled task:", error);
18864
19145
  try {
18865
19146
  const { getTaskStore } = await import("./tasks-NUFMZNV5.js");
18866
- const { TaskDependencyResolver } = await import("./task-dependency-resolver-5I62EU67.js");
18867
- const { getDatabase: getDatabase2 } = await import("./memory-O5NYYWF3.js");
19147
+ const { TaskDependencyResolver } = await import("./task-dependency-resolver-KRQRZKAD.js");
19148
+ const { getDatabase: getDatabase2 } = await import("./memory-WSP5MEER.js");
18868
19149
  const db = getDatabase2().getDb();
18869
19150
  const taskStore = getTaskStore(db);
18870
19151
  const match = message.text.match(/^\[TASK:([^\]]+)\]/);
@@ -18902,6 +19183,13 @@ ${blue} \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u250
18902
19183
  };
18903
19184
  async function main(configPath) {
18904
19185
  const app = new TonnetApp(configPath);
19186
+ process.on("unhandledRejection", (reason) => {
19187
+ console.error("\u26A0\uFE0F Unhandled promise rejection:", reason);
19188
+ });
19189
+ process.on("uncaughtException", (error) => {
19190
+ console.error("\u{1F4A5} Uncaught exception:", error);
19191
+ process.exit(1);
19192
+ });
18905
19193
  process.on("SIGINT", async () => {
18906
19194
  await app.stop();
18907
19195
  process.exit(0);
@@ -18931,8 +19219,12 @@ export {
18931
19219
  getDefaultConfigPath,
18932
19220
  ensureWorkspace,
18933
19221
  isNewWorkspace,
19222
+ TelegramUserClient,
18934
19223
  generateWallet,
18935
19224
  saveWallet,
19225
+ loadWallet,
19226
+ walletExists,
19227
+ importWallet,
18936
19228
  TonnetApp,
18937
19229
  main
18938
19230
  };