@truecarry/mcp 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/cli.js +328 -1512
  2. package/dist/factory.d.ts +35 -21
  3. package/dist/factory.d.ts.map +1 -1
  4. package/dist/index.cjs +455 -4113
  5. package/dist/index.d.ts +5 -16
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +455 -4100
  8. package/dist/services/McpWalletService.d.ts +25 -129
  9. package/dist/services/McpWalletService.d.ts.map +1 -1
  10. package/dist/tools/balance-tools.d.ts +61 -0
  11. package/dist/tools/balance-tools.d.ts.map +1 -0
  12. package/dist/tools/index.d.ts +3 -7
  13. package/dist/tools/index.d.ts.map +1 -1
  14. package/dist/tools/{swap.d.ts → swap-tools.d.ts} +6 -49
  15. package/dist/tools/swap-tools.d.ts.map +1 -0
  16. package/dist/tools/transfer-tools.d.ts +79 -0
  17. package/dist/tools/transfer-tools.d.ts.map +1 -0
  18. package/dist/tools/types.d.ts +21 -0
  19. package/dist/tools/types.d.ts.map +1 -0
  20. package/dist/types/config.d.ts +12 -36
  21. package/dist/types/config.d.ts.map +1 -1
  22. package/dist/types/index.d.ts +1 -4
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/dist/adapters/InMemoryStorageAdapter.d.ts +0 -49
  26. package/dist/adapters/InMemoryStorageAdapter.d.ts.map +0 -1
  27. package/dist/adapters/LocalSignerAdapter.d.ts +0 -107
  28. package/dist/adapters/LocalSignerAdapter.d.ts.map +0 -1
  29. package/dist/adapters/SqliteSignerAdapter.d.ts +0 -119
  30. package/dist/adapters/SqliteSignerAdapter.d.ts.map +0 -1
  31. package/dist/adapters/SqliteStorageAdapter.d.ts +0 -81
  32. package/dist/adapters/SqliteStorageAdapter.d.ts.map +0 -1
  33. package/dist/adapters/TelegramUserContextProvider.d.ts +0 -70
  34. package/dist/adapters/TelegramUserContextProvider.d.ts.map +0 -1
  35. package/dist/adapters/index.d.ts +0 -19
  36. package/dist/adapters/index.d.ts.map +0 -1
  37. package/dist/core/LimitsManager.d.ts +0 -59
  38. package/dist/core/LimitsManager.d.ts.map +0 -1
  39. package/dist/core/PendingTransactionManager.d.ts +0 -122
  40. package/dist/core/PendingTransactionManager.d.ts.map +0 -1
  41. package/dist/core/UserScopedSigner.d.ts +0 -96
  42. package/dist/core/UserScopedSigner.d.ts.map +0 -1
  43. package/dist/core/UserScopedStorage.d.ts +0 -59
  44. package/dist/core/UserScopedStorage.d.ts.map +0 -1
  45. package/dist/core/index.d.ts +0 -15
  46. package/dist/core/index.d.ts.map +0 -1
  47. package/dist/services/WalletService.d.ts +0 -144
  48. package/dist/services/WalletService.d.ts.map +0 -1
  49. package/dist/storage/SecureStorage.d.ts +0 -79
  50. package/dist/storage/SecureStorage.d.ts.map +0 -1
  51. package/dist/tools/balance.d.ts +0 -167
  52. package/dist/tools/balance.d.ts.map +0 -1
  53. package/dist/tools/mcp-tools.d.ts +0 -439
  54. package/dist/tools/mcp-tools.d.ts.map +0 -1
  55. package/dist/tools/swap.d.ts.map +0 -1
  56. package/dist/tools/transfer.d.ts +0 -146
  57. package/dist/tools/transfer.d.ts.map +0 -1
  58. package/dist/tools/wallet.d.ts +0 -138
  59. package/dist/tools/wallet.d.ts.map +0 -1
  60. package/dist/types/signer.d.ts +0 -120
  61. package/dist/types/signer.d.ts.map +0 -1
  62. package/dist/types/storage.d.ts +0 -41
  63. package/dist/types/storage.d.ts.map +0 -1
  64. package/dist/types/user-context.d.ts +0 -48
  65. package/dist/types/user-context.d.ts.map +0 -1
package/dist/cli.js CHANGED
@@ -21893,7 +21893,7 @@ var WalletKitError = class WalletKitError extends Error {
21893
21893
  function asBase64(data) {
21894
21894
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(data)) throw new Error("Not a valid base64");
21895
21895
  try {
21896
- if (Buffer.from(data, "base64").toString("base64") !== data) throw new Error("Not a valid base64");
21896
+ ParseBase64(data);
21897
21897
  } catch (_e) {
21898
21898
  throw new Error("Not a valid base64");
21899
21899
  }
@@ -23814,36 +23814,22 @@ var TONConnectStoredSessionManager = class {
23814
23814
  async getSession(sessionId) {
23815
23815
  return this.sessions.get(sessionId);
23816
23816
  }
23817
- async getSessionByDomain(domain) {
23818
- let host;
23819
- try {
23820
- host = new URL(domain).host;
23817
+ async getSessions(filter) {
23818
+ let sessions = Array.from(this.sessions.values());
23819
+ if (!filter) return sessions;
23820
+ let domain;
23821
+ if (filter.domain) try {
23822
+ domain = new URL(filter.domain).host;
23821
23823
  } catch {
23822
- return;
23823
- }
23824
- for (const session of this.sessions.values()) if (session.domain === host) return this.getSession(session.sessionId);
23825
- }
23826
- /**
23827
- * Get all sessions as array
23828
- */
23829
- async getSessions() {
23830
- return Array.from(this.sessions.values());
23831
- }
23832
- /**
23833
- * Get sessions for specific wallet by wallet ID
23834
- */
23835
- async getSessionsForWallet(walletId) {
23836
- return (await this.getSessions()).filter((session) => session.walletId === walletId);
23837
- }
23838
- /**
23839
- * Update session activity timestamp
23840
- */
23841
- async updateSessionActivity(sessionId) {
23842
- const session = this.sessions.get(sessionId);
23843
- if (session) {
23844
- session.lastActivityAt = (/* @__PURE__ */ new Date()).toISOString();
23845
- await this.persistSessions();
23846
- }
23824
+ domain = filter.domain;
23825
+ }
23826
+ return sessions.filter((session) => {
23827
+ let isIncluded = true;
23828
+ if (filter.walletId) isIncluded = isIncluded && session.walletId === filter.walletId;
23829
+ if (filter.domain) isIncluded = isIncluded && session.domain === domain;
23830
+ if (filter.isJsBridge !== void 0) isIncluded = isIncluded && session.isJsBridge === filter.isJsBridge;
23831
+ return isIncluded;
23832
+ });
23847
23833
  }
23848
23834
  /**
23849
23835
  * Remove session by ID
@@ -23851,11 +23837,8 @@ var TONConnectStoredSessionManager = class {
23851
23837
  async removeSession(sessionId) {
23852
23838
  if (this.sessions.delete(sessionId)) await this.persistSessions();
23853
23839
  }
23854
- /**
23855
- * Remove all sessions for a wallet by wallet ID or wallet adapter
23856
- */
23857
- async removeSessionsForWallet(walletId) {
23858
- const sessionsToRemove = await this.getSessionsForWallet(walletId);
23840
+ async removeSessions(filter) {
23841
+ const sessionsToRemove = await this.getSessions(filter);
23859
23842
  let removedCount = 0;
23860
23843
  for (const session of sessionsToRemove) if (this.sessions.delete(session.sessionId)) removedCount++;
23861
23844
  if (removedCount > 0) await this.persistSessions();
@@ -64265,13 +64248,15 @@ var BridgeManager = class {
64265
64248
  isJsBridge: true,
64266
64249
  tabId: messageInfo.tabId,
64267
64250
  domain: messageInfo.domain,
64268
- messageId: messageInfo.messageId
64251
+ messageId: messageInfo.messageId,
64252
+ walletId: messageInfo.walletId
64269
64253
  });
64270
64254
  else if (event.method == "restoreConnection") this.eventEmitter?.emit("restoreConnection", {
64271
64255
  ...event,
64272
64256
  tabId: messageInfo.tabId,
64273
64257
  domain: messageInfo.domain,
64274
- messageId: messageInfo.messageId
64258
+ messageId: messageInfo.messageId,
64259
+ walletId: messageInfo.walletId
64275
64260
  });
64276
64261
  else if (event.method == "send" && event?.params?.length === 1) this.eventQueue.push({
64277
64262
  ...event,
@@ -64279,7 +64264,8 @@ var BridgeManager = class {
64279
64264
  isJsBridge: true,
64280
64265
  tabId: messageInfo.tabId,
64281
64266
  domain: messageInfo.domain,
64282
- messageId: messageInfo.messageId
64267
+ messageId: messageInfo.messageId,
64268
+ walletId: messageInfo.walletId
64283
64269
  });
64284
64270
  this.processBridgeEvents().catch((error) => {
64285
64271
  log$21.error("Error in background event processing", { error });
@@ -64331,7 +64317,8 @@ var BridgeManager = class {
64331
64317
  isJsBridge: event?.isJsBridge,
64332
64318
  tabId: event?.tabId,
64333
64319
  messageId: event?.messageId,
64334
- traceId: event?.traceId
64320
+ traceId: event?.traceId,
64321
+ walletId: event?.walletId
64335
64322
  };
64336
64323
  if (!rawEvent.traceId) rawEvent.traceId = v7_default();
64337
64324
  await this.sessionManager.initialize();
@@ -64349,7 +64336,12 @@ var BridgeManager = class {
64349
64336
  };
64350
64337
  }
64351
64338
  } else if (rawEvent.domain) {
64352
- const session = await this.sessionManager.getSessionByDomain(rawEvent.domain);
64339
+ const sessions = await this.sessionManager.getSessions({
64340
+ walletId: event.walletId,
64341
+ domain: rawEvent.domain,
64342
+ isJsBridge: rawEvent.isJsBridge
64343
+ });
64344
+ const session = sessions.length > 0 ? sessions[0] : void 0;
64353
64345
  if (session?.walletId) rawEvent.walletId = session.walletId;
64354
64346
  if (session?.walletAddress) rawEvent.walletAddress = session.walletAddress;
64355
64347
  if (session?.sessionId) rawEvent.from = session.sessionId;
@@ -68159,9 +68151,6 @@ async function MnemonicToKeyPair(mnemonic, mnemonicType = "ton") {
68159
68151
  supportedTypes: ["ton", "bip39"]
68160
68152
  });
68161
68153
  }
68162
- async function CreateTonMnemonic() {
68163
- return (0, import_dist$1.mnemonicNew)(24);
68164
- }
68165
68154
 
68166
68155
  //#endregion
68167
68156
  //#region ../walletkit/dist/esm/utils/sign.js
@@ -70109,6 +70098,7 @@ var DefiManagerError = class extends Error {
70109
70098
  static NO_DEFAULT_PROVIDER = "NO_DEFAULT_PROVIDER";
70110
70099
  static NETWORK_ERROR = "NETWORK_ERROR";
70111
70100
  static INVALID_PARAMS = "INVALID_PARAMS";
70101
+ static INVALID_PROVIDER = "INVALID_PROVIDER";
70112
70102
  code;
70113
70103
  details;
70114
70104
  constructor(message, code, details) {
@@ -70150,36 +70140,42 @@ var SwapError = class extends DefiManagerError {
70150
70140
  */
70151
70141
  var DefiManager = class {
70152
70142
  providers = /* @__PURE__ */ new Map();
70153
- defaultProvider;
70143
+ defaultProviderId;
70154
70144
  /**
70155
70145
  * Register a swap provider
70156
70146
  * @param name - Unique name for the provider
70157
70147
  * @param provider - Provider instance
70158
70148
  */
70159
- registerProvider(name, provider) {
70160
- this.providers.set(name, provider);
70161
- if (!this.defaultProvider) this.defaultProvider = name;
70149
+ /**
70150
+ * Register a swap provider
70151
+ * @param provider - Provider instance
70152
+ */
70153
+ registerProvider(provider) {
70154
+ const providerId = provider.providerId;
70155
+ if (!providerId) throw this.createError("Provider must have a providerId", DefiManagerError.INVALID_PROVIDER);
70156
+ this.providers.set(providerId, provider);
70157
+ if (!this.defaultProviderId) this.defaultProviderId = providerId;
70162
70158
  }
70163
70159
  /**
70164
70160
  * Set the default provider to use when none is specified
70165
- * @param name - Provider name
70161
+ * @param providerId - Provider name
70166
70162
  * @throws DefiManagerError if provider not found
70167
70163
  */
70168
- setDefaultProvider(name) {
70169
- if (!this.providers.has(name)) throw this.createError(`Provider '${name}' not registered`, DefiManagerError.PROVIDER_NOT_FOUND, {
70170
- provider: name,
70164
+ setDefaultProvider(providerId) {
70165
+ if (!this.providers.has(providerId)) throw this.createError(`Provider '${providerId}' not registered`, DefiManagerError.PROVIDER_NOT_FOUND, {
70166
+ provider: providerId,
70171
70167
  registered: Array.from(this.providers.keys())
70172
70168
  });
70173
- this.defaultProvider = name;
70169
+ this.defaultProviderId = providerId;
70174
70170
  }
70175
70171
  /**
70176
70172
  * Get a provider by name, or the default provider
70177
- * @param name - Optional provider name
70173
+ * @param providerId - Optional provider name
70178
70174
  * @returns Provider instance
70179
70175
  * @throws DefiManagerError if provider not found or no default set
70180
70176
  */
70181
- getProvider(name) {
70182
- const providerName = name || this.defaultProvider;
70177
+ getProvider(providerId) {
70178
+ const providerName = providerId || this.defaultProviderId;
70183
70179
  if (!providerName) throw this.createError("No default provider set. Register a provider first.", DefiManagerError.NO_DEFAULT_PROVIDER);
70184
70180
  const provider = this.providers.get(providerName);
70185
70181
  if (!provider) throw this.createError(`Provider '${providerName}' not found`, DefiManagerError.PROVIDER_NOT_FOUND, {
@@ -70197,11 +70193,11 @@ var DefiManager = class {
70197
70193
  }
70198
70194
  /**
70199
70195
  * Check if a provider is registered
70200
- * @param name - Provider name
70196
+ * @param providerId - Provider id
70201
70197
  * @returns True if provider exists
70202
70198
  */
70203
- hasProvider(name) {
70204
- return this.providers.has(name);
70199
+ hasProvider(providerId) {
70200
+ return this.providers.has(providerId);
70205
70201
  }
70206
70202
  };
70207
70203
 
@@ -70229,14 +70225,12 @@ var SwapManager = class extends DefiManager {
70229
70225
  * @returns Promise resolving to swap quote
70230
70226
  */
70231
70227
  async getQuote(params, provider) {
70232
- if (params.amountFrom && params.amountTo) throw new SwapError("Cannot specify both amountFrom and amountTo", SwapError.INVALID_PARAMS);
70233
- if (!params.amountFrom && !params.amountTo) throw new SwapError("Must specify either amountFrom or amountTo", SwapError.INVALID_PARAMS);
70234
70228
  log$10.debug("Getting swap quote", {
70235
70229
  fromToken: params.fromToken,
70236
70230
  toToken: params.toToken,
70237
- amountFrom: params.amountFrom,
70238
- amountTo: params.amountTo,
70239
- provider: provider || this.defaultProvider
70231
+ amount: params.amount,
70232
+ isReverseSwap: params.isReverseSwap,
70233
+ provider: provider || this.defaultProviderId
70240
70234
  });
70241
70235
  try {
70242
70236
  const quote = await this.getProvider(provider).getQuote(params);
@@ -70263,7 +70257,7 @@ var SwapManager = class extends DefiManager {
70263
70257
  async buildSwapTransaction(params, provider) {
70264
70258
  log$10.debug("Building swap transaction", {
70265
70259
  userAddress: params.userAddress,
70266
- provider: provider || this.defaultProvider
70260
+ provider: provider || this.defaultProviderId
70267
70261
  });
70268
70262
  try {
70269
70263
  const transaction = await this.getProvider(provider).buildSwapTransaction(params);
@@ -71530,23 +71524,28 @@ var TonWalletKit = class {
71530
71524
  this.eventEmitter.on("restoreConnection", async (event) => {
71531
71525
  if (!event.domain) {
71532
71526
  log$5.error("Domain is required for restore connection");
71533
- return;
71527
+ return this.sendErrorConnectResponse(event);
71534
71528
  }
71535
- const session = await this.sessionManager.getSessionByDomain(event.domain);
71529
+ const sessions = await this.sessionManager.getSessions({
71530
+ walletId: event.walletId,
71531
+ domain: event.domain,
71532
+ isJsBridge: true
71533
+ });
71534
+ const session = sessions.length > 0 ? sessions[0] : void 0;
71536
71535
  if (!session) {
71537
71536
  log$5.error("Session not found for domain", { domain: event.domain });
71538
- return;
71537
+ return this.sendErrorConnectResponse(event);
71539
71538
  }
71540
71539
  const wallet = session.walletId ? this.walletManager?.getWallet(session.walletId) : void 0;
71541
71540
  if (!wallet) {
71542
71541
  log$5.error("Wallet not found for session", { walletId: session.walletId });
71543
- return;
71542
+ return this.sendErrorConnectResponse(event);
71544
71543
  }
71545
71544
  const walletAddress = wallet.getAddress();
71546
71545
  const walletStateInit = await wallet.getStateInit();
71547
71546
  const publicKey = wallet.getPublicKey().replace("0x", "");
71548
71547
  const deviceInfo = getDeviceInfoForWallet(wallet, this.config.deviceInfo);
71549
- const connectResponse = {
71548
+ const tonConnectEvent = {
71550
71549
  event: "connect",
71551
71550
  id: Date.now(),
71552
71551
  payload: {
@@ -71560,9 +71559,20 @@ var TonWalletKit = class {
71560
71559
  }]
71561
71560
  }
71562
71561
  };
71563
- this.bridgeManager.sendJsBridgeResponse(event?.tabId?.toString() || "", true, event?.id ?? event?.messageId, connectResponse);
71562
+ this.bridgeManager.sendJsBridgeResponse(event?.tabId?.toString() || "", true, event?.id ?? event?.messageId, tonConnectEvent);
71564
71563
  });
71565
71564
  }
71565
+ async sendErrorConnectResponse(event) {
71566
+ const tonConnectEvent = {
71567
+ event: "connect_error",
71568
+ id: Date.now(),
71569
+ payload: {
71570
+ code: CONNECT_EVENT_ERROR_CODES.UNKNOWN_APP_ERROR,
71571
+ message: ""
71572
+ }
71573
+ };
71574
+ await this.bridgeManager.sendJsBridgeResponse(event?.tabId?.toString() || "", true, event?.id ?? event?.messageId, tonConnectEvent);
71575
+ }
71566
71576
  /**
71567
71577
  * Initialize all components
71568
71578
  */
@@ -71667,7 +71677,7 @@ var TonWalletKit = class {
71667
71677
  if (!wallet) throw new WalletKitError(ERROR_CODES.WALLET_NOT_FOUND, "Wallet not found for removal", void 0, { walletId });
71668
71678
  await this.eventProcessor.stopProcessing(wallet.getAddress());
71669
71679
  await this.walletManager.removeWallet(walletId);
71670
- await this.sessionManager.removeSessionsForWallet(walletId);
71680
+ await this.sessionManager.removeSessions({ walletId });
71671
71681
  }
71672
71682
  async clearWallets() {
71673
71683
  await this.ensureInitialized();
@@ -87854,15 +87864,21 @@ function unwrapObservable(originalMethod) {
87854
87864
  *
87855
87865
  */
87856
87866
  const tokenToAddress = (token) => {
87857
- if (token === "TON") return "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c";
87858
- return import_dist$2.Address.parse(token).toRawString();
87867
+ if (token.type === "ton") return "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c";
87868
+ return import_dist$2.Address.parse(token.value).toRawString();
87859
87869
  };
87860
87870
  const addressToToken = (address) => {
87861
- if (address === "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c") return "TON";
87871
+ if (address === "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c") return { type: "ton" };
87862
87872
  try {
87863
- return import_dist$2.Address.parseRaw(address).toString();
87873
+ return {
87874
+ type: "jetton",
87875
+ value: import_dist$2.Address.parseRaw(address).toString()
87876
+ };
87864
87877
  } catch {
87865
- return address;
87878
+ return {
87879
+ type: "jetton",
87880
+ value: address
87881
+ };
87866
87882
  }
87867
87883
  };
87868
87884
  const toOmnistonAddress = (address, network) => {
@@ -87929,8 +87945,10 @@ var OmnistonSwapProvider = class extends SwapProvider {
87929
87945
  referrerFeeBps;
87930
87946
  flexibleReferrerFee;
87931
87947
  omniston$;
87948
+ providerId;
87932
87949
  constructor(config) {
87933
87950
  super();
87951
+ this.providerId = config?.providerId ?? "omniston";
87934
87952
  this.apiUrl = config?.apiUrl ?? "wss://omni-ws.ston.fi";
87935
87953
  this.defaultSlippageBps = config?.defaultSlippageBps ?? 100;
87936
87954
  this.quoteTimeoutMs = config?.quoteTimeoutMs ?? 1e4;
@@ -87950,8 +87968,8 @@ var OmnistonSwapProvider = class extends SwapProvider {
87950
87968
  log$1.debug("Getting Omniston quote", {
87951
87969
  fromToken: params.fromToken,
87952
87970
  toToken: params.toToken,
87953
- amountFrom: params.amountFrom,
87954
- amountTo: params.amountTo
87971
+ amount: params.amount,
87972
+ isReverseSwap: params.isReverseSwap
87955
87973
  });
87956
87974
  try {
87957
87975
  const bidAssetAddress = tokenToAddress(params.fromToken);
@@ -87961,7 +87979,7 @@ var OmnistonSwapProvider = class extends SwapProvider {
87961
87979
  const referrerFeeBps = params.providerOptions?.referrerFeeBps ?? this.referrerFeeBps;
87962
87980
  const flexibleReferrerFee = params.providerOptions?.flexibleReferrerFee ?? this.flexibleReferrerFee;
87963
87981
  const quoteRequest = {
87964
- amount: params.amountFrom ? { bidUnits: params.amountFrom } : { askUnits: params.amountTo },
87982
+ amount: params.isReverseSwap ? { askUnits: params.amount } : { bidUnits: params.amount },
87965
87983
  settlementMethods: [SettlementMethod.SETTLEMENT_METHOD_SWAP],
87966
87984
  bidAssetAddress: toOmnistonAddress(bidAssetAddress, params.network),
87967
87985
  askAssetAddress: toOmnistonAddress(askAssetAddress, params.network),
@@ -88095,7 +88113,7 @@ var OmnistonSwapProvider = class extends SwapProvider {
88095
88113
  });
88096
88114
  return {
88097
88115
  metadata,
88098
- provider: "omniston",
88116
+ providerId: this.providerId,
88099
88117
  fromToken: params.fromToken,
88100
88118
  toToken: params.toToken,
88101
88119
  fromAmount: quote.bidUnits,
@@ -88108,388 +88126,6 @@ var OmnistonSwapProvider = class extends SwapProvider {
88108
88126
  }
88109
88127
  };
88110
88128
 
88111
- //#endregion
88112
- //#region src/core/UserScopedStorage.ts
88113
- /**
88114
- * User-scoped storage wrapper.
88115
- * Automatically prefixes all keys with user namespace.
88116
- */
88117
- var UserScopedStorage = class {
88118
- storage;
88119
- userId;
88120
- prefix;
88121
- constructor(storage, userId) {
88122
- this.storage = storage;
88123
- this.userId = userId;
88124
- this.prefix = `user:${userId}:`;
88125
- }
88126
- /**
88127
- * Get the user ID this storage is scoped to
88128
- */
88129
- getUserId() {
88130
- return this.userId;
88131
- }
88132
- /**
88133
- * Build full key with user prefix
88134
- */
88135
- buildKey(key) {
88136
- return `${this.prefix}${key}`;
88137
- }
88138
- /**
88139
- * Strip user prefix from a key
88140
- */
88141
- stripPrefix(fullKey) {
88142
- if (fullKey.startsWith(this.prefix)) return fullKey.slice(this.prefix.length);
88143
- return fullKey;
88144
- }
88145
- /**
88146
- * Get a value by key (user-scoped)
88147
- */
88148
- async get(key) {
88149
- return this.storage.get(this.buildKey(key));
88150
- }
88151
- /**
88152
- * Set a value (user-scoped)
88153
- */
88154
- async set(key, value, ttlSeconds) {
88155
- return this.storage.set(this.buildKey(key), value, ttlSeconds);
88156
- }
88157
- /**
88158
- * Delete a key (user-scoped)
88159
- */
88160
- async delete(key) {
88161
- return this.storage.delete(this.buildKey(key));
88162
- }
88163
- /**
88164
- * List keys matching prefix (user-scoped)
88165
- * Returns keys with user prefix stripped.
88166
- */
88167
- async list(subPrefix) {
88168
- const fullPrefix = this.buildKey(subPrefix);
88169
- return (await this.storage.list(fullPrefix)).map((k) => this.stripPrefix(k));
88170
- }
88171
- /**
88172
- * Get the underlying storage adapter.
88173
- * Use with caution - bypasses user isolation.
88174
- */
88175
- getUnderlyingStorage() {
88176
- return this.storage;
88177
- }
88178
- };
88179
-
88180
- //#endregion
88181
- //#region src/core/UserScopedSigner.ts
88182
- /**
88183
- * User-scoped signer wrapper.
88184
- * Ensures all operations are scoped to the authenticated user.
88185
- */
88186
- var UserScopedSigner = class {
88187
- signer;
88188
- userId;
88189
- userPrefix;
88190
- constructor(signer, userId) {
88191
- this.signer = signer;
88192
- this.userId = userId;
88193
- this.userPrefix = `${userId}:`;
88194
- }
88195
- /**
88196
- * Get the user ID this signer is scoped to
88197
- */
88198
- getUserId() {
88199
- return this.userId;
88200
- }
88201
- /**
88202
- * Build user-scoped wallet ID from wallet name
88203
- */
88204
- scopedId(walletName) {
88205
- return `${this.userPrefix}${walletName}`;
88206
- }
88207
- /**
88208
- * Extract wallet name from scoped ID
88209
- */
88210
- extractName(scopedId) {
88211
- if (scopedId.startsWith(this.userPrefix)) return scopedId.slice(this.userPrefix.length);
88212
- return scopedId;
88213
- }
88214
- /**
88215
- * Check if a wallet ID belongs to this user
88216
- */
88217
- isOwnedByUser(walletId) {
88218
- return walletId.startsWith(this.userPrefix);
88219
- }
88220
- /**
88221
- * Transform wallet info to expose wallet name instead of internal ID
88222
- */
88223
- transformWalletInfo(info) {
88224
- return {
88225
- ...info,
88226
- name: this.extractName(info.walletId)
88227
- };
88228
- }
88229
- /**
88230
- * Create a new wallet (user-scoped)
88231
- */
88232
- async createWallet(params) {
88233
- const result = await this.signer.createWallet({
88234
- walletId: this.scopedId(params.name),
88235
- version: params.version,
88236
- network: params.network
88237
- });
88238
- return this.transformWalletInfo(result);
88239
- }
88240
- /**
88241
- * Import a wallet from mnemonic (user-scoped)
88242
- * Note: Mnemonic is passed to signer and stored securely, never returned
88243
- */
88244
- async importWallet(params) {
88245
- const result = await this.signer.importWallet({
88246
- walletId: this.scopedId(params.name),
88247
- mnemonic: params.mnemonic,
88248
- version: params.version,
88249
- network: params.network
88250
- });
88251
- return this.transformWalletInfo(result);
88252
- }
88253
- /**
88254
- * Get wallet by name (user-scoped)
88255
- * Returns null for both "not found" and "not owned" to prevent enumeration
88256
- */
88257
- async getWallet(walletName) {
88258
- const walletId = this.scopedId(walletName);
88259
- const wallet = await this.signer.getWallet(walletId);
88260
- if (!wallet) return null;
88261
- if (!this.isOwnedByUser(wallet.walletId)) return null;
88262
- return this.transformWalletInfo(wallet);
88263
- }
88264
- /**
88265
- * List all wallets for this user
88266
- */
88267
- async listWallets() {
88268
- const userIds = (await this.signer.listWalletIds()).filter((id) => this.isOwnedByUser(id));
88269
- return (await Promise.all(userIds.map(async (id) => {
88270
- const wallet = await this.signer.getWallet(id);
88271
- return wallet ? this.transformWalletInfo(wallet) : null;
88272
- }))).filter((w) => w !== null);
88273
- }
88274
- /**
88275
- * Delete a wallet (user-scoped)
88276
- * Returns false for both "not found" and "not owned"
88277
- */
88278
- async deleteWallet(walletName) {
88279
- const walletId = this.scopedId(walletName);
88280
- const wallet = await this.signer.getWallet(walletId);
88281
- if (!wallet || !this.isOwnedByUser(wallet.walletId)) return false;
88282
- return this.signer.deleteWallet(walletId);
88283
- }
88284
- /**
88285
- * Sign a transaction (user-scoped)
88286
- * Verifies ownership before signing
88287
- */
88288
- async signTransaction(walletName, unsignedBoc) {
88289
- const walletId = this.scopedId(walletName);
88290
- const wallet = await this.signer.getWallet(walletId);
88291
- if (!wallet || !this.isOwnedByUser(wallet.walletId)) throw new Error("Wallet not found");
88292
- return this.signer.signTransaction(walletId, unsignedBoc);
88293
- }
88294
- /**
88295
- * Sign a message (user-scoped)
88296
- * Verifies ownership before signing
88297
- */
88298
- async signMessage(walletName, message) {
88299
- const walletId = this.scopedId(walletName);
88300
- const wallet = await this.signer.getWallet(walletId);
88301
- if (!wallet || !this.isOwnedByUser(wallet.walletId)) throw new Error("Wallet not found");
88302
- return this.signer.signMessage(walletId, message);
88303
- }
88304
- /**
88305
- * Get the underlying signer adapter.
88306
- * Use with caution - bypasses user isolation.
88307
- */
88308
- getUnderlyingSigner() {
88309
- return this.signer;
88310
- }
88311
- };
88312
-
88313
- //#endregion
88314
- //#region src/core/LimitsManager.ts
88315
- /** TON has 9 decimal places */
88316
- const TON_DECIMALS$1 = 9;
88317
- /**
88318
- * LimitsManager enforces safety limits on transactions and wallet counts.
88319
- */
88320
- var LimitsManager = class {
88321
- limits;
88322
- constructor(limits) {
88323
- this.limits = {
88324
- maxTransactionTon: limits?.maxTransactionTon ?? Infinity,
88325
- dailyLimitTon: limits?.dailyLimitTon ?? Infinity,
88326
- maxWalletsPerUser: limits?.maxWalletsPerUser ?? Infinity
88327
- };
88328
- }
88329
- /**
88330
- * Check if a transaction amount is within limits
88331
- */
88332
- async checkTransactionLimit(storage, amountTon) {
88333
- if (amountTon > this.limits.maxTransactionTon) return {
88334
- allowed: false,
88335
- reason: `Transaction amount ${amountTon} TON exceeds maximum allowed ${this.limits.maxTransactionTon} TON per transaction`
88336
- };
88337
- const today = this.getTodayDate();
88338
- const usage = await this.getDailyUsage(storage, today);
88339
- const currentSpentTon = this.nanoToTon(usage.totalSpentNano);
88340
- if (currentSpentTon + amountTon > this.limits.dailyLimitTon) {
88341
- const remainingTon = Math.max(0, this.limits.dailyLimitTon - currentSpentTon);
88342
- return {
88343
- allowed: false,
88344
- reason: `Transaction would exceed daily limit of ${this.limits.dailyLimitTon} TON. Already spent: ${currentSpentTon.toFixed(2)} TON. Remaining: ${remainingTon.toFixed(2)} TON`
88345
- };
88346
- }
88347
- return { allowed: true };
88348
- }
88349
- /**
88350
- * Record a transaction for daily limit tracking
88351
- */
88352
- async recordTransaction(storage, amountTon) {
88353
- const today = this.getTodayDate();
88354
- const usage = await this.getDailyUsage(storage, today);
88355
- const newUsage = {
88356
- date: today,
88357
- totalSpentNano: (BigInt(usage.totalSpentNano) + BigInt(this.tonToNano(amountTon))).toString()
88358
- };
88359
- await storage.set(`daily:${today}`, newUsage, 9e4);
88360
- }
88361
- /**
88362
- * Check if user can create another wallet
88363
- */
88364
- async checkWalletCountLimit(currentWalletCount) {
88365
- if (currentWalletCount >= this.limits.maxWalletsPerUser) return {
88366
- allowed: false,
88367
- reason: `Maximum wallet limit of ${this.limits.maxWalletsPerUser} reached`
88368
- };
88369
- return { allowed: true };
88370
- }
88371
- /**
88372
- * Get the configured limits
88373
- */
88374
- getLimits() {
88375
- return { ...this.limits };
88376
- }
88377
- /**
88378
- * Get today's date as ISO string (YYYY-MM-DD)
88379
- */
88380
- getTodayDate() {
88381
- return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
88382
- }
88383
- /**
88384
- * Get daily usage for a specific date
88385
- */
88386
- async getDailyUsage(storage, date) {
88387
- return await storage.get(`daily:${date}`) ?? {
88388
- date,
88389
- totalSpentNano: "0"
88390
- };
88391
- }
88392
- /**
88393
- * Convert TON to nanoTON string
88394
- */
88395
- tonToNano(ton) {
88396
- return BigInt(Math.floor(ton * Math.pow(10, TON_DECIMALS$1))).toString();
88397
- }
88398
- /**
88399
- * Convert nanoTON string to TON
88400
- */
88401
- nanoToTon(nano) {
88402
- return Number(BigInt(nano)) / Math.pow(10, TON_DECIMALS$1);
88403
- }
88404
- };
88405
-
88406
- //#endregion
88407
- //#region src/core/PendingTransactionManager.ts
88408
- /** Default pending transaction TTL in seconds (5 minutes) */
88409
- const DEFAULT_PENDING_TTL_SECONDS = 300;
88410
- /**
88411
- * PendingTransactionManager handles the confirmation flow for transactions.
88412
- */
88413
- var PendingTransactionManager = class {
88414
- ttlSeconds;
88415
- constructor(ttlSeconds = DEFAULT_PENDING_TTL_SECONDS) {
88416
- this.ttlSeconds = ttlSeconds;
88417
- }
88418
- /**
88419
- * Generate a unique transaction ID
88420
- */
88421
- generateId() {
88422
- return `tx_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
88423
- }
88424
- /**
88425
- * Create a pending transaction
88426
- */
88427
- async createPending(storage, params) {
88428
- const id = this.generateId();
88429
- const now = /* @__PURE__ */ new Date();
88430
- const expiresAt = new Date(now.getTime() + this.ttlSeconds * 1e3);
88431
- const pending = {
88432
- id,
88433
- type: params.type,
88434
- walletName: params.walletName,
88435
- createdAt: now.toISOString(),
88436
- expiresAt: expiresAt.toISOString(),
88437
- description: params.description,
88438
- data: params.data
88439
- };
88440
- await storage.set(`pending:${id}`, pending, this.ttlSeconds);
88441
- return pending;
88442
- }
88443
- /**
88444
- * Get a pending transaction by ID
88445
- */
88446
- async getPending(storage, transactionId) {
88447
- const pending = await storage.get(`pending:${transactionId}`);
88448
- if (!pending) return null;
88449
- if (new Date(pending.expiresAt) < /* @__PURE__ */ new Date()) {
88450
- await this.deletePending(storage, transactionId);
88451
- return null;
88452
- }
88453
- return pending;
88454
- }
88455
- /**
88456
- * List all pending transactions for the user
88457
- */
88458
- async listPending(storage) {
88459
- const keys = await storage.list("pending:");
88460
- const now = /* @__PURE__ */ new Date();
88461
- const transactions = [];
88462
- for (const key of keys) {
88463
- const pending = await storage.get(key);
88464
- if (pending && new Date(pending.expiresAt) >= now) transactions.push(pending);
88465
- }
88466
- return transactions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
88467
- }
88468
- /**
88469
- * Delete a pending transaction
88470
- */
88471
- async deletePending(storage, transactionId) {
88472
- return storage.delete(`pending:${transactionId}`);
88473
- }
88474
- /**
88475
- * Mark a pending transaction as confirmed (delete it)
88476
- * The actual execution is handled by the caller
88477
- */
88478
- async confirmPending(storage, transactionId) {
88479
- const pending = await this.getPending(storage, transactionId);
88480
- if (!pending) return null;
88481
- await this.deletePending(storage, transactionId);
88482
- return pending;
88483
- }
88484
- /**
88485
- * Cancel a pending transaction
88486
- */
88487
- async cancelPending(storage, transactionId) {
88488
- if (!await this.getPending(storage, transactionId)) return false;
88489
- return this.deletePending(storage, transactionId);
88490
- }
88491
- };
88492
-
88493
88129
  //#endregion
88494
88130
  //#region src/services/McpWalletService.ts
88495
88131
  /**
@@ -88500,38 +88136,46 @@ var PendingTransactionManager = class {
88500
88136
  *
88501
88137
  */
88502
88138
  /**
88503
- * McpWalletService - Multi-user wallet service with adapter support
88139
+ * McpWalletService - Simplified wallet service for MCP server
88504
88140
  *
88505
- * This service wraps wallet operations with:
88506
- * - User isolation via UserScopedSigner and UserScopedStorage
88507
- * - Transaction limits via LimitsManager
88508
- * - Confirmation flow via PendingTransactionManager
88141
+ * This service wraps a single Wallet instance for operations.
88142
+ * Wallet management (create/import/list/remove) is handled externally.
88509
88143
  *
88510
- * Unlike the standalone WalletService, this service is designed for
88511
- * multi-user environments like Telegram bots.
88144
+ * For multi-user scenarios (e.g., Telegram bots), use this service
88145
+ * with user-specific wallet instances.
88512
88146
  */
88513
88147
  /**
88514
- * McpWalletService manages wallet operations for multi-user MCP deployments.
88148
+ * McpWalletService manages wallet operations for a single wallet.
88515
88149
  */
88516
- var McpWalletService = class {
88150
+ var McpWalletService = class McpWalletService {
88517
88151
  config;
88518
- limitsManager;
88519
- pendingManager;
88152
+ wallet;
88520
88153
  kit = null;
88521
- loadedWallets = /* @__PURE__ */ new Map();
88522
88154
  constructor(config) {
88523
88155
  this.config = config;
88524
- this.limitsManager = new LimitsManager(config.limits);
88525
- this.pendingManager = new PendingTransactionManager();
88156
+ this.wallet = config.wallet;
88157
+ }
88158
+ static async create(config) {
88159
+ const wallet = await wrapWalletInterface(config.wallet);
88160
+ return new McpWalletService({
88161
+ ...config,
88162
+ wallet
88163
+ });
88164
+ }
88165
+ /**
88166
+ * Get wallet address
88167
+ */
88168
+ getAddress() {
88169
+ return this.wallet.getAddress();
88526
88170
  }
88527
88171
  /**
88528
- * Get Network instance from network name
88172
+ * Get wallet network
88529
88173
  */
88530
- getNetwork(networkName) {
88531
- return networkName === "mainnet" ? Network.mainnet() : Network.testnet();
88174
+ getNetwork() {
88175
+ return this.wallet.getNetwork().chainId === Network.mainnet().chainId ? "mainnet" : "testnet";
88532
88176
  }
88533
88177
  /**
88534
- * Initialize TonWalletKit
88178
+ * Initialize TonWalletKit (for swap operations)
88535
88179
  */
88536
88180
  async getKit() {
88537
88181
  if (!this.kit) {
@@ -88554,169 +88198,27 @@ var McpWalletService = class {
88554
88198
  });
88555
88199
  await this.kit.waitForReady();
88556
88200
  const omnistonProvider = new OmnistonSwapProvider({ defaultSlippageBps: 100 });
88557
- this.kit.swap.registerProvider("omniston", omnistonProvider);
88558
- this.kit.swap.setDefaultProvider("omniston");
88201
+ this.kit.swap.registerProvider(omnistonProvider);
88559
88202
  }
88560
88203
  return this.kit;
88561
88204
  }
88562
88205
  /**
88563
- * Create user-scoped storage wrapper
88564
- */
88565
- createUserStorage(userId) {
88566
- return new UserScopedStorage(this.config.storage, userId);
88567
- }
88568
- /**
88569
- * Create user-scoped signer wrapper
88570
- */
88571
- createUserSigner(userId) {
88572
- return new UserScopedSigner(this.config.signer, userId);
88573
- }
88574
- /**
88575
- * Get limits manager
88576
- */
88577
- getLimitsManager() {
88578
- return this.limitsManager;
88579
- }
88580
- /**
88581
- * Get pending transaction manager
88582
- */
88583
- getPendingManager() {
88584
- return this.pendingManager;
88585
- }
88586
- /**
88587
- * Check if confirmation is required
88588
- */
88589
- requiresConfirmation() {
88590
- return this.config.requireConfirmation ?? false;
88591
- }
88592
- /**
88593
- * Create a new wallet for a user
88594
- */
88595
- async createWallet(userSigner, userStorage, name, version = "v5r1", networkName = this.config.defaultNetwork ?? "mainnet") {
88596
- const existingWallets = await userSigner.listWallets();
88597
- const limitCheck = await this.limitsManager.checkWalletCountLimit(existingWallets.length);
88598
- if (!limitCheck.allowed) throw new Error(limitCheck.reason);
88599
- const walletInfo = await userSigner.createWallet({
88600
- name,
88601
- version,
88602
- network: networkName
88603
- });
88604
- const metadata = {
88605
- name: walletInfo.name,
88606
- address: walletInfo.address,
88607
- network: walletInfo.network,
88608
- version: walletInfo.version,
88609
- createdAt: walletInfo.createdAt
88610
- };
88611
- await userStorage.set(`wallet:${name}`, metadata);
88612
- return {
88613
- name: walletInfo.name,
88614
- address: walletInfo.address,
88615
- network: walletInfo.network
88616
- };
88617
- }
88618
- /**
88619
- * Import a wallet for a user
88620
- */
88621
- async importWallet(userSigner, userStorage, name, mnemonic, version = "v5r1", networkName = this.config.defaultNetwork ?? "mainnet") {
88622
- const existingWallets = await userSigner.listWallets();
88623
- const limitCheck = await this.limitsManager.checkWalletCountLimit(existingWallets.length);
88624
- if (!limitCheck.allowed) throw new Error(limitCheck.reason);
88625
- const walletInfo = await userSigner.importWallet({
88626
- name,
88627
- mnemonic,
88628
- version,
88629
- network: networkName
88630
- });
88631
- const metadata = {
88632
- name: walletInfo.name,
88633
- address: walletInfo.address,
88634
- network: walletInfo.network,
88635
- version: walletInfo.version,
88636
- createdAt: walletInfo.createdAt
88637
- };
88638
- await userStorage.set(`wallet:${name}`, metadata);
88639
- return {
88640
- name: walletInfo.name,
88641
- address: walletInfo.address,
88642
- network: walletInfo.network
88643
- };
88644
- }
88645
- /**
88646
- * List all wallets for a user
88647
- */
88648
- async listWallets(userSigner) {
88649
- return (await userSigner.listWallets()).map((w) => ({
88650
- name: w.name,
88651
- address: w.address,
88652
- network: w.network,
88653
- version: w.version,
88654
- createdAt: w.createdAt
88655
- }));
88656
- }
88657
- /**
88658
- * Remove a wallet for a user
88659
- */
88660
- async removeWallet(userSigner, userStorage, name) {
88661
- const deleted = await userSigner.deleteWallet(name);
88662
- if (deleted) await userStorage.delete(`wallet:${name}`);
88663
- return deleted;
88664
- }
88665
- /**
88666
- * Get or load a wallet for balance/transfer operations
88667
- */
88668
- async getWalletForOperations(userSigner, name) {
88669
- const walletInfo = await userSigner.getWallet(name);
88670
- if (!walletInfo) throw new Error("Wallet not found");
88671
- const network = this.getNetwork(walletInfo.network);
88672
- const walletId = createWalletId(network, walletInfo.address);
88673
- if (this.loadedWallets.has(walletId)) return this.loadedWallets.get(walletId);
88674
- const signer = userSigner.getUnderlyingSigner();
88675
- if (typeof signer.getLoadedWallet === "function") {
88676
- const scopedId = `${userSigner.getUserId()}:${name}`;
88677
- const wallet = await signer.getLoadedWallet(scopedId);
88678
- this.loadedWallets.set(walletId, wallet);
88679
- return wallet;
88680
- }
88681
- if (typeof signer.getStoredWallet === "function") {
88682
- const scopedId = `${userSigner.getUserId()}:${name}`;
88683
- const storedWallet = signer.getStoredWallet(scopedId);
88684
- if (storedWallet) {
88685
- const kit = await this.getKit();
88686
- const signerInstance = await Signer.fromMnemonic(storedWallet.mnemonic, { type: "ton" });
88687
- const walletAdapter = storedWallet.version === "v5r1" ? await WalletV5R1Adapter.create(signerInstance, {
88688
- client: kit.getApiClient(network),
88689
- network
88690
- }) : await WalletV4R2Adapter.create(signerInstance, {
88691
- client: kit.getApiClient(network),
88692
- network
88693
- });
88694
- let wallet = await kit.addWallet(walletAdapter);
88695
- if (!wallet) wallet = kit.getWallet(walletId);
88696
- if (!wallet) throw new Error("Failed to load wallet");
88697
- this.loadedWallets.set(walletId, wallet);
88698
- return wallet;
88699
- }
88700
- }
88701
- throw new Error("Unable to load wallet for operations");
88702
- }
88703
- /**
88704
88206
  * Get TON balance
88705
88207
  */
88706
- async getBalance(userSigner, walletName) {
88707
- return (await this.getWalletForOperations(userSigner, walletName)).getBalance();
88208
+ async getBalance() {
88209
+ return this.wallet.getBalance();
88708
88210
  }
88709
88211
  /**
88710
88212
  * Get Jetton balance
88711
88213
  */
88712
- async getJettonBalance(userSigner, walletName, jettonAddress) {
88713
- return (await this.getWalletForOperations(userSigner, walletName)).getJettonBalance(jettonAddress);
88214
+ async getJettonBalance(jettonAddress) {
88215
+ return this.wallet.getJettonBalance(jettonAddress);
88714
88216
  }
88715
88217
  /**
88716
88218
  * Get all Jettons
88717
88219
  */
88718
- async getJettons(userSigner, walletName) {
88719
- return (await (await this.getWalletForOperations(userSigner, walletName)).getJettons({ pagination: {
88220
+ async getJettons() {
88221
+ return (await this.wallet.getJettons({ pagination: {
88720
88222
  limit: 100,
88721
88223
  offset: 0
88722
88224
  } })).jettons.map((j) => ({
@@ -88728,15 +88230,11 @@ var McpWalletService = class {
88728
88230
  }));
88729
88231
  }
88730
88232
  /**
88731
- * Get transaction history for a wallet
88233
+ * Get transaction history using events API
88732
88234
  */
88733
- /**
88734
- * Get transaction history using events API (like demo wallet)
88735
- */
88736
- async getTransactions(userSigner, walletName, limit = 20) {
88737
- const wallet = await this.getWalletForOperations(userSigner, walletName);
88738
- const address = wallet.getAddress();
88739
- const response = await wallet.getClient().getEvents({
88235
+ async getTransactions(limit = 20) {
88236
+ const address = this.wallet.getAddress();
88237
+ const response = await this.wallet.getClient().getEvents({
88740
88238
  account: address,
88741
88239
  limit
88742
88240
  });
@@ -88781,49 +88279,16 @@ var McpWalletService = class {
88781
88279
  return results;
88782
88280
  }
88783
88281
  /**
88784
- * Send TON (with optional confirmation flow)
88785
- */
88786
- async sendTon(userSigner, userStorage, walletName, toAddress, amountNano, amountTon, comment) {
88787
- const limitCheck = await this.limitsManager.checkTransactionLimit(userStorage, parseFloat(amountTon));
88788
- if (!limitCheck.allowed) return {
88789
- success: false,
88790
- message: limitCheck.reason
88791
- };
88792
- if (this.requiresConfirmation()) {
88793
- const pending = await this.pendingManager.createPending(userStorage, {
88794
- type: "send_ton",
88795
- walletName,
88796
- description: `Send ${amountTon} TON to ${toAddress}${comment ? ` (${comment})` : ""}`,
88797
- data: {
88798
- type: "send_ton",
88799
- toAddress,
88800
- amountNano,
88801
- amountTon,
88802
- comment
88803
- }
88804
- });
88805
- return {
88806
- success: true,
88807
- message: `Transaction pending confirmation. ID: ${pending.id}`,
88808
- pendingTransactionId: pending.id
88809
- };
88810
- }
88811
- return this.executeTonTransfer(userSigner, userStorage, walletName, toAddress, amountNano, comment);
88812
- }
88813
- /**
88814
- * Execute TON transfer (internal)
88282
+ * Send TON
88815
88283
  */
88816
- async executeTonTransfer(userSigner, userStorage, walletName, toAddress, amountNano, comment) {
88284
+ async sendTon(toAddress, amountNano, comment) {
88817
88285
  try {
88818
- const wallet = await this.getWalletForOperations(userSigner, walletName);
88819
- const tx = await wallet.createTransferTonTransaction({
88286
+ const tx = await this.wallet.createTransferTonTransaction({
88820
88287
  recipientAddress: toAddress,
88821
88288
  transferAmount: amountNano,
88822
88289
  comment
88823
88290
  });
88824
- await wallet.sendTransaction(tx);
88825
- const amountTon = Number(BigInt(amountNano)) / 1e9;
88826
- await this.limitsManager.recordTransaction(userStorage, amountTon);
88291
+ await this.wallet.sendTransaction(tx);
88827
88292
  return {
88828
88293
  success: true,
88829
88294
  message: `Successfully sent ${amountNano} nanoTON to ${toAddress}`
@@ -88836,46 +88301,17 @@ var McpWalletService = class {
88836
88301
  }
88837
88302
  }
88838
88303
  /**
88839
- * Send Jetton (with optional confirmation flow)
88304
+ * Send Jetton
88840
88305
  */
88841
- async sendJetton(userSigner, userStorage, walletName, toAddress, jettonAddress, amountRaw, amountHuman, symbol, decimals, comment) {
88842
- if (this.requiresConfirmation()) {
88843
- const pending = await this.pendingManager.createPending(userStorage, {
88844
- type: "send_jetton",
88845
- walletName,
88846
- description: `Send ${amountHuman} ${symbol ?? "tokens"} to ${toAddress}${comment ? ` (${comment})` : ""}`,
88847
- data: {
88848
- type: "send_jetton",
88849
- toAddress,
88850
- jettonAddress,
88851
- amountRaw,
88852
- amountHuman,
88853
- symbol,
88854
- decimals,
88855
- comment
88856
- }
88857
- });
88858
- return {
88859
- success: true,
88860
- message: `Transaction pending confirmation. ID: ${pending.id}`,
88861
- pendingTransactionId: pending.id
88862
- };
88863
- }
88864
- return this.executeJettonTransfer(userSigner, walletName, toAddress, jettonAddress, amountRaw, comment);
88865
- }
88866
- /**
88867
- * Execute Jetton transfer (internal)
88868
- */
88869
- async executeJettonTransfer(userSigner, walletName, toAddress, jettonAddress, amountRaw, comment) {
88306
+ async sendJetton(toAddress, jettonAddress, amountRaw, comment) {
88870
88307
  try {
88871
- const wallet = await this.getWalletForOperations(userSigner, walletName);
88872
- const tx = await wallet.createTransferJettonTransaction({
88308
+ const tx = await this.wallet.createTransferJettonTransaction({
88873
88309
  recipientAddress: toAddress,
88874
88310
  jettonAddress,
88875
88311
  transferAmount: amountRaw,
88876
88312
  comment
88877
88313
  });
88878
- await wallet.sendTransaction(tx);
88314
+ await this.wallet.sendTransaction(tx);
88879
88315
  return {
88880
88316
  success: true,
88881
88317
  message: `Successfully sent jettons to ${toAddress}`
@@ -88890,75 +88326,46 @@ var McpWalletService = class {
88890
88326
  /**
88891
88327
  * Get swap quote
88892
88328
  */
88893
- async getSwapQuote(userSigner, walletName, fromToken, toToken, amount, slippageBps) {
88894
- const walletInfo = await userSigner.getWallet(walletName);
88895
- if (!walletInfo) throw new Error("Wallet not found");
88896
- const network = this.getNetwork(walletInfo.network);
88329
+ async getSwapQuote(fromToken, toToken, amount, slippageBps) {
88330
+ const network = this.wallet.getNetwork();
88897
88331
  const kit = await this.getKit();
88898
88332
  const params = {
88899
- fromToken: fromToken === "TON" ? "TON" : fromToken,
88900
- toToken: toToken === "TON" ? "TON" : toToken,
88901
- amountFrom: amount,
88333
+ fromToken: fromToken === "TON" ? { type: "ton" } : {
88334
+ type: "jetton",
88335
+ value: fromToken
88336
+ },
88337
+ toToken: toToken === "TON" ? { type: "ton" } : {
88338
+ type: "jetton",
88339
+ value: toToken
88340
+ },
88341
+ amount,
88902
88342
  network,
88903
88343
  slippageBps
88904
88344
  };
88905
88345
  const quote = await kit.swap.getQuote(params);
88906
88346
  return {
88907
88347
  quote,
88908
- fromToken: typeof quote.fromToken === "string" ? quote.fromToken : quote.fromToken,
88909
- toToken: typeof quote.toToken === "string" ? quote.toToken : quote.toToken,
88348
+ fromToken: quote.fromToken.type === "ton" ? "TON" : quote.fromToken.value,
88349
+ toToken: quote.toToken.type === "ton" ? "TON" : quote.toToken.value,
88910
88350
  fromAmount: quote.fromAmount,
88911
88351
  toAmount: quote.toAmount,
88912
88352
  minReceived: quote.minReceived,
88913
- provider: quote.provider,
88353
+ provider: quote.providerId,
88914
88354
  expiresAt: quote.expiresAt
88915
88355
  };
88916
88356
  }
88917
88357
  /**
88918
- * Execute swap (with optional confirmation flow)
88919
- */
88920
- async executeSwap(userSigner, userStorage, walletName, quote) {
88921
- if (this.requiresConfirmation()) {
88922
- const pending = await this.pendingManager.createPending(userStorage, {
88923
- type: "swap",
88924
- walletName,
88925
- description: `Swap ${quote.fromAmount} ${quote.fromToken} for ${quote.toAmount} ${quote.toToken}`,
88926
- data: {
88927
- type: "swap",
88928
- fromToken: String(quote.fromToken),
88929
- toToken: String(quote.toToken),
88930
- fromAmount: quote.fromAmount,
88931
- toAmount: quote.toAmount,
88932
- minReceived: quote.minReceived,
88933
- provider: quote.provider,
88934
- quoteJson: JSON.stringify(quote)
88935
- }
88936
- });
88937
- return {
88938
- success: true,
88939
- message: `Swap pending confirmation. ID: ${pending.id}`,
88940
- pendingTransactionId: pending.id
88941
- };
88942
- }
88943
- return this.executeSwapInternal(userSigner, walletName, quote);
88944
- }
88945
- /**
88946
- * Execute swap (internal)
88358
+ * Execute swap
88947
88359
  */
88948
- async executeSwapInternal(userSigner, walletName, quote) {
88360
+ async executeSwap(quote) {
88949
88361
  try {
88950
- const [wallet, kit, walletInfo] = await Promise.all([
88951
- this.getWalletForOperations(userSigner, walletName),
88952
- this.getKit(),
88953
- userSigner.getWallet(walletName)
88954
- ]);
88955
- if (!walletInfo) throw new Error("Wallet not found");
88362
+ const kit = await this.getKit();
88956
88363
  const params = {
88957
88364
  quote,
88958
- userAddress: walletInfo.address
88365
+ userAddress: this.wallet.getAddress()
88959
88366
  };
88960
88367
  const tx = await kit.swap.buildSwapTransaction(params);
88961
- await wallet.sendTransaction(tx);
88368
+ await this.wallet.sendTransaction(tx);
88962
88369
  return {
88963
88370
  success: true,
88964
88371
  message: `Successfully swapped ${quote.fromAmount} ${quote.fromToken} for ${quote.toAmount} ${quote.toToken}`
@@ -88971,52 +88378,11 @@ var McpWalletService = class {
88971
88378
  }
88972
88379
  }
88973
88380
  /**
88974
- * Confirm a pending transaction
88975
- */
88976
- async confirmTransaction(userSigner, userStorage, transactionId) {
88977
- const pending = await this.pendingManager.confirmPending(userStorage, transactionId);
88978
- if (!pending) return {
88979
- success: false,
88980
- message: "Transaction not found or expired"
88981
- };
88982
- switch (pending.data.type) {
88983
- case "send_ton": {
88984
- const data = pending.data;
88985
- return this.executeTonTransfer(userSigner, userStorage, pending.walletName, data.toAddress, data.amountNano, data.comment);
88986
- }
88987
- case "send_jetton": {
88988
- const data = pending.data;
88989
- return this.executeJettonTransfer(userSigner, pending.walletName, data.toAddress, data.jettonAddress, data.amountRaw, data.comment);
88990
- }
88991
- case "swap": {
88992
- const data = pending.data;
88993
- const quote = JSON.parse(data.quoteJson);
88994
- return this.executeSwapInternal(userSigner, pending.walletName, quote);
88995
- }
88996
- default: return {
88997
- success: false,
88998
- message: "Unknown transaction type"
88999
- };
89000
- }
89001
- }
89002
- /**
89003
- * Cancel a pending transaction
89004
- */
89005
- async cancelTransaction(userStorage, transactionId) {
89006
- return this.pendingManager.cancelPending(userStorage, transactionId);
89007
- }
89008
- /**
89009
- * List pending transactions
89010
- */
89011
- async listPendingTransactions(userStorage) {
89012
- return this.pendingManager.listPending(userStorage);
89013
- }
89014
- /**
89015
88381
  * Resolve contact name to address
89016
88382
  */
89017
- async resolveContact(userId, name) {
88383
+ async resolveContact(name) {
89018
88384
  if (!this.config.contacts) return null;
89019
- return this.config.contacts.resolve(userId, name);
88385
+ return this.config.contacts.resolve("default", name);
89020
88386
  }
89021
88387
  /**
89022
88388
  * Close and cleanup
@@ -89026,12 +88392,11 @@ var McpWalletService = class {
89026
88392
  await this.kit.close();
89027
88393
  this.kit = null;
89028
88394
  }
89029
- this.loadedWallets.clear();
89030
88395
  }
89031
88396
  };
89032
88397
 
89033
88398
  //#endregion
89034
- //#region src/tools/mcp-tools.ts
88399
+ //#region src/tools/balance-tools.ts
89035
88400
  /**
89036
88401
  * Copyright (c) TonTech.
89037
88402
  *
@@ -89039,185 +88404,24 @@ var McpWalletService = class {
89039
88404
  * LICENSE file in the root directory of this source tree.
89040
88405
  *
89041
88406
  */
89042
- /**
89043
- * MCP tools for multi-user deployments with authentication
89044
- *
89045
- * These tools wrap the McpWalletService with user isolation.
89046
- * They are used by the createTonWalletMCP factory.
89047
- */
89048
- /**
89049
- * Converts a human-readable amount to raw units.
89050
- */
89051
- function toRawAmount(amount, decimals) {
89052
- const [intPart, fracPart = ""] = amount.split(".");
89053
- return (intPart + fracPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
89054
- }
89055
- const TON_DECIMALS = 9;
89056
- const createWalletSchema = z.object({
89057
- name: z.string().min(1).describe("Unique name for the wallet"),
89058
- version: z.enum(["v5r1", "v4r2"]).optional().describe("Wallet version (v5r1 recommended, v4r2 for legacy compatibility). Defaults to v5r1."),
89059
- network: z.enum(["mainnet", "testnet"]).optional().describe("Network to create the wallet on. Defaults to the server configured network.")
89060
- });
89061
- const importWalletSchema = z.object({
89062
- name: z.string().min(1).describe("Unique name for the wallet"),
89063
- mnemonic: z.string().describe("24-word mnemonic phrase separated by spaces"),
89064
- version: z.enum(["v5r1", "v4r2"]).optional().describe("Wallet version (v5r1 recommended, v4r2 for legacy compatibility). Defaults to v5r1."),
89065
- network: z.enum(["mainnet", "testnet"]).optional().describe("Network to import the wallet on. Defaults to the server configured network.")
89066
- });
89067
- const removeWalletSchema = z.object({ name: z.string().min(1).describe("Name of the wallet to remove") });
89068
- function createMcpWalletTools(_walletService, wrapHandler) {
89069
- return {
89070
- create_wallet: {
89071
- description: "Create a new TON wallet. The wallet is created securely and you will receive the address. No seed phrase is exposed.",
89072
- inputSchema: createWalletSchema,
89073
- handler: wrapHandler(async (args, userId, service) => {
89074
- const userSigner = service.createUserSigner(userId);
89075
- const userStorage = service.createUserStorage(userId);
89076
- try {
89077
- const result = await service.createWallet(userSigner, userStorage, args.name, args.version, args.network);
89078
- return { content: [{
89079
- type: "text",
89080
- text: JSON.stringify({
89081
- success: true,
89082
- wallet: {
89083
- name: result.name,
89084
- address: result.address,
89085
- network: result.network
89086
- }
89087
- }, null, 2)
89088
- }] };
89089
- } catch (error) {
89090
- return {
89091
- content: [{
89092
- type: "text",
89093
- text: JSON.stringify({
89094
- success: false,
89095
- error: error instanceof Error ? error.message : "Unknown error"
89096
- })
89097
- }],
89098
- isError: true
89099
- };
89100
- }
89101
- })
89102
- },
89103
- import_wallet: {
89104
- description: "Import an existing TON wallet using a 24-word mnemonic phrase. The mnemonic is stored securely and never exposed.",
89105
- inputSchema: importWalletSchema,
89106
- handler: wrapHandler(async (args, userId, service) => {
89107
- const mnemonicWords = args.mnemonic.trim().split(/\s+/);
89108
- if (mnemonicWords.length !== 24) return {
89109
- content: [{
89110
- type: "text",
89111
- text: JSON.stringify({
89112
- success: false,
89113
- error: `Invalid mnemonic: expected 24 words, got ${mnemonicWords.length}`
89114
- })
89115
- }],
89116
- isError: true
89117
- };
89118
- const userSigner = service.createUserSigner(userId);
89119
- const userStorage = service.createUserStorage(userId);
89120
- try {
89121
- const result = await service.importWallet(userSigner, userStorage, args.name, mnemonicWords, args.version, args.network);
89122
- return { content: [{
89123
- type: "text",
89124
- text: JSON.stringify({
89125
- success: true,
89126
- wallet: {
89127
- name: result.name,
89128
- address: result.address,
89129
- network: result.network
89130
- }
89131
- }, null, 2)
89132
- }] };
89133
- } catch (error) {
89134
- return {
89135
- content: [{
89136
- type: "text",
89137
- text: JSON.stringify({
89138
- success: false,
89139
- error: error instanceof Error ? error.message : "Unknown error"
89140
- })
89141
- }],
89142
- isError: true
89143
- };
89144
- }
89145
- })
89146
- },
89147
- list_wallets: {
89148
- description: "List all your stored TON wallets with their addresses and metadata.",
89149
- inputSchema: z.object({}),
89150
- handler: wrapHandler(async (_args, userId, service) => {
89151
- const userSigner = service.createUserSigner(userId);
89152
- const wallets = await service.listWallets(userSigner);
89153
- return { content: [{
89154
- type: "text",
89155
- text: JSON.stringify({
89156
- success: true,
89157
- wallets: wallets.map((w) => ({
89158
- name: w.name,
89159
- address: w.address,
89160
- network: w.network,
89161
- version: w.version,
89162
- createdAt: w.createdAt
89163
- })),
89164
- count: wallets.length
89165
- }, null, 2)
89166
- }] };
89167
- })
89168
- },
89169
- remove_wallet: {
89170
- description: "Remove a wallet from storage. This action cannot be undone!",
89171
- inputSchema: removeWalletSchema,
89172
- handler: wrapHandler(async (args, userId, service) => {
89173
- const userSigner = service.createUserSigner(userId);
89174
- const userStorage = service.createUserStorage(userId);
89175
- if (!await service.removeWallet(userSigner, userStorage, args.name)) return {
89176
- content: [{
89177
- type: "text",
89178
- text: JSON.stringify({
89179
- success: false,
89180
- error: "Wallet not found"
89181
- })
89182
- }],
89183
- isError: true
89184
- };
89185
- return { content: [{
89186
- type: "text",
89187
- text: JSON.stringify({
89188
- success: true,
89189
- message: `Wallet "${args.name}" has been removed`
89190
- })
89191
- }] };
89192
- })
89193
- }
89194
- };
89195
- }
89196
- const getBalanceSchema = z.object({ wallet: z.string().min(1).describe("Name of the wallet to check balance") });
89197
- const getJettonBalanceSchema = z.object({
89198
- wallet: z.string().min(1).describe("Name of the wallet"),
89199
- jettonAddress: z.string().min(1).describe("Jetton master contract address")
89200
- });
89201
- const getJettonsSchema = z.object({ wallet: z.string().min(1).describe("Name of the wallet") });
89202
- const getTransactionsSchema = z.object({
89203
- wallet: z.string().min(1).describe("Name of the wallet to get transactions for"),
89204
- limit: z.number().min(1).max(100).optional().describe("Maximum number of transactions to return (default: 20, max: 100)")
89205
- });
89206
- function createMcpBalanceTools(_walletService, wrapHandler) {
88407
+ const getBalanceSchema = z.object({});
88408
+ const getJettonBalanceSchema = z.object({ jettonAddress: z.string().min(1).describe("Jetton master contract address") });
88409
+ const getJettonsSchema = z.object({});
88410
+ const getTransactionsSchema = z.object({ limit: z.number().min(1).max(100).optional().describe("Maximum number of transactions to return (default: 20, max: 100)") });
88411
+ function createMcpBalanceTools(service) {
89207
88412
  return {
89208
88413
  get_balance: {
89209
- description: "Get the TON balance of a wallet. Returns both human-readable and raw (nanoTON) amounts.",
88414
+ description: "Get the TON balance of the wallet. Returns both human-readable and raw (nanoTON) amounts.",
89210
88415
  inputSchema: getBalanceSchema,
89211
- handler: wrapHandler(async (args, userId, service) => {
89212
- const userSigner = service.createUserSigner(userId);
88416
+ handler: async () => {
89213
88417
  try {
89214
- const balance = await service.getBalance(userSigner, args.wallet);
88418
+ const balance = await service.getBalance();
89215
88419
  const balanceTon = Number(BigInt(balance)) / 1e9;
89216
88420
  return { content: [{
89217
88421
  type: "text",
89218
88422
  text: JSON.stringify({
89219
88423
  success: true,
89220
- wallet: args.wallet,
88424
+ address: service.getAddress(),
89221
88425
  balance: `${balanceTon} TON`,
89222
88426
  balanceNano: balance
89223
88427
  }, null, 2)
@@ -89234,20 +88438,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
89234
88438
  isError: true
89235
88439
  };
89236
88440
  }
89237
- })
88441
+ }
89238
88442
  },
89239
88443
  get_jetton_balance: {
89240
- description: "Get the balance of a specific Jetton (token) in a wallet.",
88444
+ description: "Get the balance of a specific Jetton (token) in the wallet.",
89241
88445
  inputSchema: getJettonBalanceSchema,
89242
- handler: wrapHandler(async (args, userId, service) => {
89243
- const userSigner = service.createUserSigner(userId);
88446
+ handler: async (args) => {
89244
88447
  try {
89245
- const balance = await service.getJettonBalance(userSigner, args.wallet, args.jettonAddress);
88448
+ const balance = await service.getJettonBalance(args.jettonAddress);
89246
88449
  return { content: [{
89247
88450
  type: "text",
89248
88451
  text: JSON.stringify({
89249
88452
  success: true,
89250
- wallet: args.wallet,
89251
88453
  jettonAddress: args.jettonAddress,
89252
88454
  balance
89253
88455
  }, null, 2)
@@ -89264,20 +88466,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
89264
88466
  isError: true
89265
88467
  };
89266
88468
  }
89267
- })
88469
+ }
89268
88470
  },
89269
88471
  get_jettons: {
89270
- description: "List all Jettons (tokens) in a wallet with their balances and metadata.",
88472
+ description: "List all Jettons (tokens) in the wallet with their balances and metadata.",
89271
88473
  inputSchema: getJettonsSchema,
89272
- handler: wrapHandler(async (args, userId, service) => {
89273
- const userSigner = service.createUserSigner(userId);
88474
+ handler: async () => {
89274
88475
  try {
89275
- const jettons = await service.getJettons(userSigner, args.wallet);
88476
+ const jettons = await service.getJettons();
89276
88477
  return { content: [{
89277
88478
  type: "text",
89278
88479
  text: JSON.stringify({
89279
88480
  success: true,
89280
- wallet: args.wallet,
89281
88481
  jettons,
89282
88482
  count: jettons.length
89283
88483
  }, null, 2)
@@ -89294,20 +88494,18 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
89294
88494
  isError: true
89295
88495
  };
89296
88496
  }
89297
- })
88497
+ }
89298
88498
  },
89299
88499
  get_transactions: {
89300
- description: "Get recent transaction history for a wallet. Returns events with actions like TON transfers, Jetton transfers, swaps, and more.",
88500
+ description: "Get recent transaction history for the wallet. Returns events with actions like TON transfers, Jetton transfers, swaps, and more.",
89301
88501
  inputSchema: getTransactionsSchema,
89302
- handler: wrapHandler(async (args, userId, service) => {
89303
- const userSigner = service.createUserSigner(userId);
88502
+ handler: async (args) => {
89304
88503
  try {
89305
- const transactions = await service.getTransactions(userSigner, args.wallet, args.limit ?? 20);
88504
+ const transactions = await service.getTransactions(args.limit ?? 20);
89306
88505
  return { content: [{
89307
88506
  type: "text",
89308
88507
  text: JSON.stringify({
89309
88508
  success: true,
89310
- wallet: args.wallet,
89311
88509
  transactions: transactions.map((tx) => ({
89312
88510
  eventId: tx.eventId,
89313
88511
  timestamp: tx.timestamp,
@@ -89355,33 +88553,50 @@ function createMcpBalanceTools(_walletService, wrapHandler) {
89355
88553
  isError: true
89356
88554
  };
89357
88555
  }
89358
- })
88556
+ }
89359
88557
  }
89360
88558
  };
89361
88559
  }
88560
+
88561
+ //#endregion
88562
+ //#region src/tools/types.ts
88563
+ /**
88564
+ * Converts a human-readable amount to raw units.
88565
+ */
88566
+ function toRawAmount(amount, decimals) {
88567
+ const [intPart, fracPart = ""] = amount.split(".");
88568
+ return (intPart + fracPart.padEnd(decimals, "0").slice(0, decimals)).replace(/^0+/, "") || "0";
88569
+ }
88570
+ const TON_DECIMALS = 9;
88571
+
88572
+ //#endregion
88573
+ //#region src/tools/transfer-tools.ts
88574
+ /**
88575
+ * Copyright (c) TonTech.
88576
+ *
88577
+ * This source code is licensed under the MIT license found in the
88578
+ * LICENSE file in the root directory of this source tree.
88579
+ *
88580
+ */
89362
88581
  const sendTonSchema = z.object({
89363
- wallet: z.string().min(1).describe("Name of the wallet to send from"),
89364
88582
  toAddress: z.string().min(1).describe("Recipient TON address"),
89365
88583
  amount: z.string().min(1).describe("Amount of TON to send (e.g., \"1.5\" for 1.5 TON)"),
89366
88584
  comment: z.string().optional().describe("Optional comment/memo for the transaction")
89367
88585
  });
89368
88586
  const sendJettonSchema = z.object({
89369
- wallet: z.string().min(1).describe("Name of the wallet to send from"),
89370
88587
  toAddress: z.string().min(1).describe("Recipient TON address"),
89371
88588
  jettonAddress: z.string().min(1).describe("Jetton master contract address"),
89372
88589
  amount: z.string().min(1).describe("Amount of tokens to send in human-readable format"),
89373
88590
  comment: z.string().optional().describe("Optional comment/memo for the transaction")
89374
88591
  });
89375
- function createMcpTransferTools(_walletService, wrapHandler) {
88592
+ function createMcpTransferTools(service) {
89376
88593
  return {
89377
88594
  send_ton: {
89378
- description: "Send TON from a wallet to an address. Amount is in TON (e.g., \"1.5\" means 1.5 TON). May require confirmation if enabled.",
88595
+ description: "Send TON from the wallet to an address. Amount is in TON (e.g., \"1.5\" means 1.5 TON).",
89379
88596
  inputSchema: sendTonSchema,
89380
- handler: wrapHandler(async (args, userId, service) => {
89381
- const userSigner = service.createUserSigner(userId);
89382
- const userStorage = service.createUserStorage(userId);
88597
+ handler: async (args) => {
89383
88598
  const rawAmount = toRawAmount(args.amount, TON_DECIMALS);
89384
- const result = await service.sendTon(userSigner, userStorage, args.wallet, args.toAddress, rawAmount, args.amount, args.comment);
88599
+ const result = await service.sendTon(args.toAddress, rawAmount, args.comment);
89385
88600
  if (!result.success) return {
89386
88601
  content: [{
89387
88602
  type: "text",
@@ -89398,26 +88613,22 @@ function createMcpTransferTools(_walletService, wrapHandler) {
89398
88613
  success: true,
89399
88614
  message: result.message,
89400
88615
  details: {
89401
- from: args.wallet,
89402
88616
  to: args.toAddress,
89403
88617
  amount: `${args.amount} TON`,
89404
- comment: args.comment || null,
89405
- pendingTransactionId: result.pendingTransactionId || null
88618
+ comment: args.comment || null
89406
88619
  }
89407
88620
  }, null, 2)
89408
88621
  }] };
89409
- })
88622
+ }
89410
88623
  },
89411
88624
  send_jetton: {
89412
- description: "Send Jettons (tokens) from a wallet to an address. Amount is in human-readable format. May require confirmation if enabled.",
88625
+ description: "Send Jettons (tokens) from the wallet to an address. Amount is in human-readable format.",
89413
88626
  inputSchema: sendJettonSchema,
89414
- handler: wrapHandler(async (args, userId, service) => {
89415
- const userSigner = service.createUserSigner(userId);
89416
- const userStorage = service.createUserStorage(userId);
88627
+ handler: async (args) => {
89417
88628
  let decimals;
89418
88629
  let symbol;
89419
88630
  try {
89420
- const jetton = (await service.getJettons(userSigner, args.wallet)).find((j) => j.address.toLowerCase() === args.jettonAddress.toLowerCase());
88631
+ const jetton = (await service.getJettons()).find((j) => j.address.toLowerCase() === args.jettonAddress.toLowerCase());
89421
88632
  if (jetton) {
89422
88633
  decimals = jetton.decimals;
89423
88634
  symbol = jetton.symbol;
@@ -89445,7 +88656,7 @@ function createMcpTransferTools(_walletService, wrapHandler) {
89445
88656
  isError: true
89446
88657
  };
89447
88658
  const rawAmount = toRawAmount(args.amount, decimals);
89448
- const result = await service.sendJetton(userSigner, userStorage, args.wallet, args.toAddress, args.jettonAddress, rawAmount, args.amount, symbol, decimals, args.comment);
88659
+ const result = await service.sendJetton(args.toAddress, args.jettonAddress, rawAmount, args.comment);
89449
88660
  if (!result.success) return {
89450
88661
  content: [{
89451
88662
  type: "text",
@@ -89462,19 +88673,27 @@ function createMcpTransferTools(_walletService, wrapHandler) {
89462
88673
  success: true,
89463
88674
  message: result.message,
89464
88675
  details: {
89465
- from: args.wallet,
89466
88676
  to: args.toAddress,
89467
88677
  jettonAddress: args.jettonAddress,
89468
88678
  amount: `${args.amount} ${symbol || "tokens"}`,
89469
- comment: args.comment || null,
89470
- pendingTransactionId: result.pendingTransactionId || null
88679
+ comment: args.comment || null
89471
88680
  }
89472
88681
  }, null, 2)
89473
88682
  }] };
89474
- })
88683
+ }
89475
88684
  }
89476
88685
  };
89477
88686
  }
88687
+
88688
+ //#endregion
88689
+ //#region src/tools/swap-tools.ts
88690
+ /**
88691
+ * Copyright (c) TonTech.
88692
+ *
88693
+ * This source code is licensed under the MIT license found in the
88694
+ * LICENSE file in the root directory of this source tree.
88695
+ *
88696
+ */
89478
88697
  const quoteCache = /* @__PURE__ */ new Map();
89479
88698
  function generateQuoteId() {
89480
88699
  return `quote_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -89484,32 +88703,26 @@ function cleanExpiredQuotes() {
89484
88703
  for (const [id, data] of quoteCache.entries()) if (data.expiresAt < now) quoteCache.delete(id);
89485
88704
  }
89486
88705
  const getSwapQuoteSchema = z.object({
89487
- wallet: z.string().min(1).describe("Name of the wallet to swap from"),
89488
88706
  fromToken: z.string().min(1).describe("Token to swap from (\"TON\" or jetton address)"),
89489
88707
  toToken: z.string().min(1).describe("Token to swap to (\"TON\" or jetton address)"),
89490
88708
  amount: z.string().min(1).describe("Amount to swap in raw units"),
89491
88709
  slippageBps: z.number().optional().describe("Slippage tolerance in basis points (default 100 = 1%)")
89492
88710
  });
89493
- const executeSwapSchema = z.object({
89494
- wallet: z.string().min(1).describe("Name of the wallet to execute swap from"),
89495
- quoteId: z.string().min(1).describe("Quote ID returned from get_swap_quote")
89496
- });
89497
- function createMcpSwapTools(_walletService, wrapHandler) {
88711
+ const executeSwapSchema = z.object({ quoteId: z.string().min(1).describe("Quote ID returned from get_swap_quote") });
88712
+ function createMcpSwapTools(service) {
89498
88713
  return {
89499
88714
  get_swap_quote: {
89500
88715
  description: "Get a quote for swapping tokens. Returns a quote ID to use with execute_swap.",
89501
88716
  inputSchema: getSwapQuoteSchema,
89502
- handler: wrapHandler(async (args, userId, service) => {
89503
- const userSigner = service.createUserSigner(userId);
88717
+ handler: async (args) => {
89504
88718
  try {
89505
88719
  cleanExpiredQuotes();
89506
- const result = await service.getSwapQuote(userSigner, args.wallet, args.fromToken, args.toToken, args.amount, args.slippageBps);
88720
+ const result = await service.getSwapQuote(args.fromToken, args.toToken, args.amount, args.slippageBps);
89507
88721
  const quoteId = generateQuoteId();
89508
88722
  const expiresAt = result.expiresAt ? result.expiresAt * 1e3 : Date.now() + 6e4;
89509
88723
  quoteCache.set(quoteId, {
89510
88724
  quote: result.quote,
89511
- expiresAt,
89512
- userId
88725
+ expiresAt
89513
88726
  });
89514
88727
  return { content: [{
89515
88728
  type: "text",
@@ -89538,14 +88751,12 @@ function createMcpSwapTools(_walletService, wrapHandler) {
89538
88751
  isError: true
89539
88752
  };
89540
88753
  }
89541
- })
88754
+ }
89542
88755
  },
89543
88756
  execute_swap: {
89544
- description: "Execute a token swap using a quote. May require confirmation if enabled.",
88757
+ description: "Execute a token swap using a quote.",
89545
88758
  inputSchema: executeSwapSchema,
89546
- handler: wrapHandler(async (args, userId, service) => {
89547
- const userSigner = service.createUserSigner(userId);
89548
- const userStorage = service.createUserStorage(userId);
88759
+ handler: async (args) => {
89549
88760
  cleanExpiredQuotes();
89550
88761
  const cachedQuote = quoteCache.get(args.quoteId);
89551
88762
  if (!cachedQuote) return {
@@ -89558,16 +88769,6 @@ function createMcpSwapTools(_walletService, wrapHandler) {
89558
88769
  }],
89559
88770
  isError: true
89560
88771
  };
89561
- if (cachedQuote.userId !== userId) return {
89562
- content: [{
89563
- type: "text",
89564
- text: JSON.stringify({
89565
- success: false,
89566
- error: "Quote not found or expired. Please get a new quote."
89567
- })
89568
- }],
89569
- isError: true
89570
- };
89571
88772
  if (cachedQuote.expiresAt < Date.now()) {
89572
88773
  quoteCache.delete(args.quoteId);
89573
88774
  return {
@@ -89581,7 +88782,7 @@ function createMcpSwapTools(_walletService, wrapHandler) {
89581
88782
  isError: true
89582
88783
  };
89583
88784
  }
89584
- const result = await service.executeSwap(userSigner, userStorage, args.wallet, cachedQuote.quote);
88785
+ const result = await service.executeSwap(cachedQuote.quote);
89585
88786
  quoteCache.delete(args.quoteId);
89586
88787
  if (!result.success) return {
89587
88788
  content: [{
@@ -89603,91 +88804,11 @@ function createMcpSwapTools(_walletService, wrapHandler) {
89603
88804
  toToken: cachedQuote.quote.toToken,
89604
88805
  fromAmount: cachedQuote.quote.fromAmount,
89605
88806
  toAmount: cachedQuote.quote.toAmount,
89606
- provider: cachedQuote.quote.provider,
89607
- pendingTransactionId: result.pendingTransactionId || null
88807
+ provider: cachedQuote.quote.providerId
89608
88808
  }
89609
88809
  }, null, 2)
89610
88810
  }] };
89611
- })
89612
- }
89613
- };
89614
- }
89615
- const confirmTransactionSchema = z.object({ transactionId: z.string().min(1).describe("ID of the pending transaction to confirm") });
89616
- const cancelTransactionSchema = z.object({ transactionId: z.string().min(1).describe("ID of the pending transaction to cancel") });
89617
- function createMcpPendingTools(_walletService, wrapHandler) {
89618
- return {
89619
- confirm_transaction: {
89620
- description: "Confirm and execute a pending transaction.",
89621
- inputSchema: confirmTransactionSchema,
89622
- handler: wrapHandler(async (args, userId, service) => {
89623
- const userSigner = service.createUserSigner(userId);
89624
- const userStorage = service.createUserStorage(userId);
89625
- const result = await service.confirmTransaction(userSigner, userStorage, args.transactionId);
89626
- if (!result.success) return {
89627
- content: [{
89628
- type: "text",
89629
- text: JSON.stringify({
89630
- success: false,
89631
- error: result.message
89632
- })
89633
- }],
89634
- isError: true
89635
- };
89636
- return { content: [{
89637
- type: "text",
89638
- text: JSON.stringify({
89639
- success: true,
89640
- message: result.message
89641
- }, null, 2)
89642
- }] };
89643
- })
89644
- },
89645
- cancel_transaction: {
89646
- description: "Cancel a pending transaction.",
89647
- inputSchema: cancelTransactionSchema,
89648
- handler: wrapHandler(async (args, userId, service) => {
89649
- const userStorage = service.createUserStorage(userId);
89650
- if (!await service.cancelTransaction(userStorage, args.transactionId)) return {
89651
- content: [{
89652
- type: "text",
89653
- text: JSON.stringify({
89654
- success: false,
89655
- error: "Transaction not found or already processed"
89656
- })
89657
- }],
89658
- isError: true
89659
- };
89660
- return { content: [{
89661
- type: "text",
89662
- text: JSON.stringify({
89663
- success: true,
89664
- message: "Transaction cancelled"
89665
- })
89666
- }] };
89667
- })
89668
- },
89669
- list_pending_transactions: {
89670
- description: "List all pending transactions awaiting confirmation.",
89671
- inputSchema: z.object({}),
89672
- handler: wrapHandler(async (_args, userId, service) => {
89673
- const userStorage = service.createUserStorage(userId);
89674
- const pending = await service.listPendingTransactions(userStorage);
89675
- return { content: [{
89676
- type: "text",
89677
- text: JSON.stringify({
89678
- success: true,
89679
- transactions: pending.map((tx) => ({
89680
- id: tx.id,
89681
- type: tx.type,
89682
- wallet: tx.walletName,
89683
- description: tx.description,
89684
- createdAt: tx.createdAt,
89685
- expiresAt: tx.expiresAt
89686
- })),
89687
- count: pending.length
89688
- }, null, 2)
89689
- }] };
89690
- })
88811
+ }
89691
88812
  }
89692
88813
  };
89693
88814
  }
@@ -89709,70 +88830,46 @@ const SERVER_VERSION = "0.1.0";
89709
88830
  /**
89710
88831
  * Create a configured TON Wallet MCP server
89711
88832
  *
89712
- * @param config - Configuration with adapters and limits
88833
+ * @param config - Configuration with wallet instance
89713
88834
  * @returns Configured McpServer instance
89714
88835
  *
89715
88836
  * @example
89716
88837
  * ```typescript
89717
- * import { createTonWalletMCP, InMemoryStorageAdapter, LocalSignerAdapter } from '@ton/mcp';
88838
+ * import { createTonWalletMCP } from '@ton/mcp';
88839
+ * import { Signer, WalletV5R1Adapter, TonWalletKit, Network } from '@ton/walletkit';
89718
88840
  *
89719
- * const server = createTonWalletMCP({
89720
- * storage: new InMemoryStorageAdapter(),
89721
- * signer: new LocalSignerAdapter(),
89722
- * userContext: {
89723
- * getUserId: async (ctx) => ctx.headers?.['x-user-id'] ?? null,
89724
- * },
89725
- * limits: {
89726
- * maxTransactionTon: 100,
89727
- * dailyLimitTon: 1000,
89728
- * maxWalletsPerUser: 10,
89729
- * },
89730
- * requireConfirmation: true,
88841
+ * // Create wallet adapter
88842
+ * const kit = new TonWalletKit({ ... });
88843
+ * const signer = await Signer.fromMnemonic(mnemonic, { type: 'ton' });
88844
+ * const walletAdapter = await WalletV5R1Adapter.create(signer, {
88845
+ * client: kit.getApiClient(Network.mainnet()),
88846
+ * network: Network.mainnet(),
89731
88847
  * });
88848
+ * const wallet = await kit.addWallet(walletAdapter);
88849
+ *
88850
+ * // Create MCP server
88851
+ * const server = createTonWalletMCP({ wallet });
89732
88852
  * ```
89733
88853
  */
89734
- function createTonWalletMCP(config) {
89735
- const walletService = new McpWalletService({
89736
- storage: config.storage,
89737
- signer: config.signer,
88854
+ async function createTonWalletMCP(config) {
88855
+ const walletService = await McpWalletService.create({
88856
+ wallet: config.wallet,
89738
88857
  contacts: config.contacts,
89739
- defaultNetwork: config.network,
89740
- limits: config.limits,
89741
- requireConfirmation: config.requireConfirmation
88858
+ networks: config.networks
89742
88859
  });
89743
88860
  const server = new McpServer({
89744
88861
  name: SERVER_NAME$1,
89745
88862
  version: SERVER_VERSION
89746
88863
  });
89747
- const authenticateUser = async (requestContext) => {
89748
- const userId = await config.userContext.getUserId(requestContext);
89749
- if (!userId) throw new Error("User authentication required");
89750
- return userId;
89751
- };
89752
- const createAuthenticatedHandler = (handler) => {
89753
- return async (args, extra) => {
89754
- const extraObj = extra;
89755
- return handler(args, await authenticateUser({
89756
- headers: extraObj?.headers,
89757
- metadata: extraObj?.meta
89758
- }), walletService);
89759
- };
89760
- };
89761
- const walletTools = createMcpWalletTools(walletService, createAuthenticatedHandler);
89762
- const balanceTools = createMcpBalanceTools(walletService, createAuthenticatedHandler);
89763
- const transferTools = createMcpTransferTools(walletService, createAuthenticatedHandler);
89764
- const swapTools = createMcpSwapTools(walletService, createAuthenticatedHandler);
89765
- const pendingTools = createMcpPendingTools(walletService, createAuthenticatedHandler);
88864
+ const balanceTools = createMcpBalanceTools(walletService);
88865
+ const transferTools = createMcpTransferTools(walletService);
88866
+ const swapTools = createMcpSwapTools(walletService);
89766
88867
  const registerTool = (name, tool) => {
89767
88868
  server.registerTool(name, {
89768
88869
  description: tool.description,
89769
88870
  inputSchema: tool.inputSchema
89770
88871
  }, tool.handler);
89771
88872
  };
89772
- registerTool("create_wallet", walletTools.create_wallet);
89773
- registerTool("import_wallet", walletTools.import_wallet);
89774
- registerTool("list_wallets", walletTools.list_wallets);
89775
- registerTool("remove_wallet", walletTools.remove_wallet);
89776
88873
  registerTool("get_balance", balanceTools.get_balance);
89777
88874
  registerTool("get_jetton_balance", balanceTools.get_jetton_balance);
89778
88875
  registerTool("get_jettons", balanceTools.get_jettons);
@@ -89781,331 +88878,9 @@ function createTonWalletMCP(config) {
89781
88878
  registerTool("send_jetton", transferTools.send_jetton);
89782
88879
  registerTool("get_swap_quote", swapTools.get_swap_quote);
89783
88880
  registerTool("execute_swap", swapTools.execute_swap);
89784
- if (config.requireConfirmation) {
89785
- registerTool("confirm_transaction", pendingTools.confirm_transaction);
89786
- registerTool("cancel_transaction", pendingTools.cancel_transaction);
89787
- registerTool("list_pending_transactions", pendingTools.list_pending_transactions);
89788
- }
89789
88881
  return server;
89790
88882
  }
89791
88883
 
89792
- //#endregion
89793
- //#region src/adapters/InMemoryStorageAdapter.ts
89794
- /**
89795
- * In-memory storage adapter for testing and development.
89796
- * Data is not persistent and will be lost on process restart.
89797
- */
89798
- var InMemoryStorageAdapter = class {
89799
- data = /* @__PURE__ */ new Map();
89800
- timers = /* @__PURE__ */ new Map();
89801
- /**
89802
- * Get a value by key
89803
- */
89804
- async get(key) {
89805
- return this.data.get(key) ?? null;
89806
- }
89807
- /**
89808
- * Set a value with optional TTL
89809
- */
89810
- async set(key, value, ttlSeconds) {
89811
- const existingTimer = this.timers.get(key);
89812
- if (existingTimer) {
89813
- clearTimeout(existingTimer);
89814
- this.timers.delete(key);
89815
- }
89816
- this.data.set(key, value);
89817
- if (ttlSeconds !== void 0 && ttlSeconds > 0) {
89818
- const timer = setTimeout(() => {
89819
- this.data.delete(key);
89820
- this.timers.delete(key);
89821
- }, ttlSeconds * 1e3);
89822
- this.timers.set(key, timer);
89823
- }
89824
- }
89825
- /**
89826
- * Delete a key
89827
- */
89828
- async delete(key) {
89829
- const timer = this.timers.get(key);
89830
- if (timer) {
89831
- clearTimeout(timer);
89832
- this.timers.delete(key);
89833
- }
89834
- return this.data.delete(key);
89835
- }
89836
- /**
89837
- * List keys matching prefix
89838
- */
89839
- async list(prefix) {
89840
- const keys = [];
89841
- for (const key of this.data.keys()) if (key.startsWith(prefix)) keys.push(key);
89842
- return keys;
89843
- }
89844
- /**
89845
- * Clear all data (useful for testing)
89846
- */
89847
- clear() {
89848
- for (const timer of this.timers.values()) clearTimeout(timer);
89849
- this.timers.clear();
89850
- this.data.clear();
89851
- }
89852
- /**
89853
- * Get the number of stored items (useful for testing)
89854
- */
89855
- size() {
89856
- return this.data.size;
89857
- }
89858
- };
89859
-
89860
- //#endregion
89861
- //#region src/adapters/LocalSignerAdapter.ts
89862
- /**
89863
- * Copyright (c) TonTech.
89864
- *
89865
- * This source code is licensed under the MIT license found in the
89866
- * LICENSE file in the root directory of this source tree.
89867
- *
89868
- */
89869
- /**
89870
- * LocalSignerAdapter - Local signer using @ton/walletkit
89871
- *
89872
- * This adapter uses TonWalletKit for wallet operations.
89873
- * For production use with encryption, extend this class or implement
89874
- * your own ISignerAdapter with proper key encryption.
89875
- *
89876
- * Note: This is a reference implementation. For production custody,
89877
- * consider using HSM, KMS, or Vault-based signers.
89878
- */
89879
- /**
89880
- * Local signer adapter using TonWalletKit.
89881
- *
89882
- * This implementation stores mnemonics in memory. For production use,
89883
- * implement encryption or use a secure key management system.
89884
- */
89885
- var LocalSignerAdapter = class {
89886
- wallets = /* @__PURE__ */ new Map();
89887
- kit = null;
89888
- loadedWallets = /* @__PURE__ */ new Map();
89889
- /**
89890
- * Get Network instance from network name
89891
- */
89892
- getNetwork(networkName) {
89893
- return networkName === "mainnet" ? Network.mainnet() : Network.testnet();
89894
- }
89895
- /**
89896
- * Initialize or get TonWalletKit instance
89897
- */
89898
- async getKit() {
89899
- if (!this.kit) {
89900
- this.kit = new TonWalletKit({
89901
- networks: {
89902
- [Network.mainnet().chainId]: {},
89903
- [Network.testnet().chainId]: {}
89904
- },
89905
- storage: new MemoryStorageAdapter()
89906
- });
89907
- await this.kit.waitForReady();
89908
- }
89909
- return this.kit;
89910
- }
89911
- /**
89912
- * Create wallet adapter from mnemonic
89913
- */
89914
- async createWalletAdapter(mnemonic, version, network) {
89915
- const kit = await this.getKit();
89916
- const signer = await Signer.fromMnemonic(mnemonic, { type: "ton" });
89917
- return {
89918
- adapter: version === "v5r1" ? await WalletV5R1Adapter.create(signer, {
89919
- client: kit.getApiClient(network),
89920
- network
89921
- }) : await WalletV4R2Adapter.create(signer, {
89922
- client: kit.getApiClient(network),
89923
- network
89924
- }),
89925
- publicKey: Buffer.from(signer.publicKey).toString("hex")
89926
- };
89927
- }
89928
- /**
89929
- * Create a new wallet with generated mnemonic
89930
- */
89931
- async createWallet(params) {
89932
- const { walletId, version, network: networkName } = params;
89933
- if (this.wallets.has(walletId)) throw new Error(`Wallet "${walletId}" already exists`);
89934
- const network = this.getNetwork(networkName);
89935
- const mnemonic = await CreateTonMnemonic();
89936
- const { adapter, publicKey } = await this.createWalletAdapter(mnemonic, version, network);
89937
- const address = adapter.getAddress();
89938
- const createdAt = (/* @__PURE__ */ new Date()).toISOString();
89939
- const storedWallet = {
89940
- walletId,
89941
- mnemonic,
89942
- publicKey,
89943
- address,
89944
- network: networkName,
89945
- version,
89946
- createdAt
89947
- };
89948
- this.wallets.set(walletId, storedWallet);
89949
- const wallet = await (await this.getKit()).addWallet(adapter);
89950
- if (wallet) this.loadedWallets.set(walletId, wallet);
89951
- return {
89952
- walletId,
89953
- publicKey,
89954
- address,
89955
- network: networkName,
89956
- version,
89957
- createdAt
89958
- };
89959
- }
89960
- /**
89961
- * Import a wallet from mnemonic
89962
- */
89963
- async importWallet(params) {
89964
- const { walletId, mnemonic, version, network: networkName } = params;
89965
- if (this.wallets.has(walletId)) throw new Error(`Wallet "${walletId}" already exists`);
89966
- if (mnemonic.length !== 24) throw new Error(`Invalid mnemonic: expected 24 words, got ${mnemonic.length}`);
89967
- const network = this.getNetwork(networkName);
89968
- const { adapter, publicKey } = await this.createWalletAdapter(mnemonic, version, network);
89969
- const address = adapter.getAddress();
89970
- const createdAt = (/* @__PURE__ */ new Date()).toISOString();
89971
- const storedWallet = {
89972
- walletId,
89973
- mnemonic,
89974
- publicKey,
89975
- address,
89976
- network: networkName,
89977
- version,
89978
- createdAt
89979
- };
89980
- this.wallets.set(walletId, storedWallet);
89981
- const wallet = await (await this.getKit()).addWallet(adapter);
89982
- if (wallet) this.loadedWallets.set(walletId, wallet);
89983
- return {
89984
- walletId,
89985
- publicKey,
89986
- address,
89987
- network: networkName,
89988
- version,
89989
- createdAt
89990
- };
89991
- }
89992
- /**
89993
- * Get wallet info by ID
89994
- */
89995
- async getWallet(walletId) {
89996
- const stored = this.wallets.get(walletId);
89997
- if (!stored) return null;
89998
- return {
89999
- walletId: stored.walletId,
90000
- publicKey: stored.publicKey,
90001
- address: stored.address,
90002
- network: stored.network,
90003
- version: stored.version,
90004
- createdAt: stored.createdAt
90005
- };
90006
- }
90007
- /**
90008
- * List all wallet IDs
90009
- */
90010
- async listWalletIds() {
90011
- return Array.from(this.wallets.keys());
90012
- }
90013
- /**
90014
- * Delete a wallet
90015
- */
90016
- async deleteWallet(walletId) {
90017
- if (!this.wallets.get(walletId)) return false;
90018
- this.loadedWallets.delete(walletId);
90019
- return this.wallets.delete(walletId);
90020
- }
90021
- /**
90022
- * Get or load a wallet for signing
90023
- */
90024
- async getWalletForSigning(walletId) {
90025
- if (this.loadedWallets.has(walletId)) return this.loadedWallets.get(walletId);
90026
- const stored = this.wallets.get(walletId);
90027
- if (!stored) throw new Error("Wallet not found");
90028
- const network = this.getNetwork(stored.network);
90029
- const { adapter } = await this.createWalletAdapter(stored.mnemonic, stored.version, network);
90030
- const kit = await this.getKit();
90031
- let wallet = await kit.addWallet(adapter);
90032
- if (!wallet) {
90033
- const kitWalletId = `${network.chainId}:${stored.address}`;
90034
- wallet = kit.getWallet(kitWalletId);
90035
- if (!wallet) throw new Error("Failed to load wallet");
90036
- }
90037
- this.loadedWallets.set(walletId, wallet);
90038
- return wallet;
90039
- }
90040
- /**
90041
- * Sign a transaction
90042
- */
90043
- async signTransaction(_walletId, _unsignedBoc) {
90044
- throw new Error("signTransaction with BOC not implemented. Use the wallet service for transaction signing.");
90045
- }
90046
- /**
90047
- * Sign a message
90048
- */
90049
- async signMessage(walletId, message) {
90050
- const stored = this.wallets.get(walletId);
90051
- if (!stored) throw new Error("Wallet not found");
90052
- const signature = await (await Signer.fromMnemonic(stored.mnemonic, { type: "ton" })).sign(message);
90053
- return Buffer.from(signature, "hex");
90054
- }
90055
- /**
90056
- * Close and cleanup
90057
- */
90058
- async close() {
90059
- if (this.kit) {
90060
- await this.kit.close();
90061
- this.kit = null;
90062
- }
90063
- this.loadedWallets.clear();
90064
- }
90065
- /**
90066
- * Get TonWalletKit instance for direct wallet operations
90067
- * Used by WalletService for balance/transfer operations
90068
- */
90069
- async getKitInstance() {
90070
- return this.getKit();
90071
- }
90072
- /**
90073
- * Get a loaded wallet by ID for direct operations
90074
- * Used by WalletService for balance/transfer operations
90075
- */
90076
- async getLoadedWallet(walletId) {
90077
- return this.getWalletForSigning(walletId);
90078
- }
90079
- /**
90080
- * Get stored wallet data (internal use only)
90081
- */
90082
- getStoredWallet(walletId) {
90083
- return this.wallets.get(walletId);
90084
- }
90085
- };
90086
-
90087
- //#endregion
90088
- //#region src/adapters/TelegramUserContextProvider.ts
90089
- /**
90090
- * Simple user context provider that always returns a fixed user ID.
90091
- * Useful for single-user CLI applications or testing.
90092
- */
90093
- var StaticUserContextProvider = class {
90094
- userId;
90095
- constructor(userId) {
90096
- this.userId = userId;
90097
- }
90098
- async getUserId() {
90099
- return this.userId;
90100
- }
90101
- async getUserMetadata() {
90102
- return {
90103
- provider: "static",
90104
- userId: this.userId
90105
- };
90106
- }
90107
- };
90108
-
90109
88884
  //#endregion
90110
88885
  //#region src/cli.ts
90111
88886
  /**
@@ -90122,12 +88897,21 @@ var StaticUserContextProvider = class {
90122
88897
  * TON wallet management tools for use with Claude Desktop or other MCP clients.
90123
88898
  *
90124
88899
  * Usage:
90125
- * npx @ton/mcp # stdio mode (default)
90126
- * npx @ton/mcp --http # HTTP server on port 3000
90127
- * npx @ton/mcp --http 8080 # HTTP server on custom port
88900
+ * npx @ton/mcp # stdio mode (default)
88901
+ * npx @ton/mcp --http # HTTP server on 0.0.0.0:3000
88902
+ * npx @ton/mcp --http 8080 # HTTP server on custom port
88903
+ * npx @ton/mcp --http --host 127.0.0.1 # HTTP server on custom host
88904
+ *
88905
+ * Environment variables:
88906
+ * NETWORK - Network to use (mainnet or testnet, default: mainnet)
88907
+ * MNEMONIC - 24-word mnemonic phrase for wallet (if not provided, a new wallet is created)
88908
+ * WALLET_VERSION - Wallet version (v5r1 or v4r2, default: v5r1)
90128
88909
  */
90129
88910
  const SERVER_NAME = "ton-mcp";
90130
88911
  const NETWORK = process.env.NETWORK || "mainnet";
88912
+ const MNEMONIC = process.env.MNEMONIC;
88913
+ const WALLET_VERSION = process.env.WALLET_VERSION || "v5r1";
88914
+ const TONCENTER_API_KEY = process.env.TONCENTER_API_KEY;
90131
88915
  function log(message) {
90132
88916
  console.error(`[${SERVER_NAME}] ${message}`);
90133
88917
  }
@@ -90136,33 +88920,66 @@ function parseArgs() {
90136
88920
  const httpIndex = args.indexOf("--http");
90137
88921
  if (httpIndex === -1) return { mode: "stdio" };
90138
88922
  const nextArg = args[httpIndex + 1];
88923
+ const port = nextArg && !nextArg.startsWith("-") ? parseInt(nextArg, 10) : 3e3;
88924
+ const hostIndex = args.indexOf("--host");
88925
+ const hostArg = hostIndex !== -1 ? args[hostIndex + 1] : void 0;
90139
88926
  return {
90140
88927
  mode: "http",
90141
- port: nextArg && !nextArg.startsWith("-") ? parseInt(nextArg, 10) : 3e3
88928
+ port,
88929
+ host: hostArg && !hostArg.startsWith("-") ? hostArg : "0.0.0.0"
90142
88930
  };
90143
88931
  }
90144
- function createAdaptersAndServer() {
90145
- const storage = new InMemoryStorageAdapter();
90146
- const signer = new LocalSignerAdapter();
88932
+ async function createWalletAndServer() {
88933
+ const network = NETWORK === "mainnet" ? Network.mainnet() : Network.testnet();
88934
+ const apiConfig = {};
88935
+ if (TONCENTER_API_KEY) {
88936
+ apiConfig.url = NETWORK === "mainnet" ? "https://toncenter.com" : "https://testnet.toncenter.com";
88937
+ apiConfig.key = TONCENTER_API_KEY;
88938
+ }
88939
+ const kit = new TonWalletKit({
88940
+ networks: { [network.chainId]: { apiClient: apiConfig } },
88941
+ storage: new MemoryStorageAdapter()
88942
+ });
88943
+ await kit.waitForReady();
88944
+ let mnemonic;
88945
+ if (MNEMONIC) {
88946
+ mnemonic = MNEMONIC.trim().split(/\s+/);
88947
+ if (mnemonic.length !== 24) throw new Error(`Invalid mnemonic: expected 24 words, got ${mnemonic.length}`);
88948
+ log("Using provided mnemonic");
88949
+ } else throw new Error("MNEMONIC is required");
88950
+ const signer = await Signer.fromMnemonic(mnemonic, { type: "ton" });
88951
+ const walletAdapter = WALLET_VERSION === "v5r1" ? await WalletV5R1Adapter.create(signer, {
88952
+ client: kit.getApiClient(network),
88953
+ network
88954
+ }) : await WalletV4R2Adapter.create(signer, {
88955
+ client: kit.getApiClient(network),
88956
+ network
88957
+ });
88958
+ let wallet = await kit.addWallet(walletAdapter);
88959
+ if (!wallet) wallet = kit.getWallet(walletAdapter.getWalletId());
88960
+ if (!wallet) throw new Error("Failed to create wallet");
88961
+ log(`Wallet address: ${wallet.getAddress()}`);
88962
+ log(`Network: ${NETWORK}`);
88963
+ log(`Version: ${WALLET_VERSION}`);
90147
88964
  return {
90148
- server: createTonWalletMCP({
90149
- storage,
90150
- signer,
90151
- userContext: new StaticUserContextProvider("cli-user"),
90152
- network: NETWORK,
90153
- requireConfirmation: false
88965
+ server: await createTonWalletMCP({
88966
+ wallet,
88967
+ networks: {
88968
+ mainnet: TONCENTER_API_KEY && NETWORK === "mainnet" ? { apiKey: TONCENTER_API_KEY } : void 0,
88969
+ testnet: TONCENTER_API_KEY && NETWORK === "testnet" ? { apiKey: TONCENTER_API_KEY } : void 0
88970
+ }
90154
88971
  }),
90155
- signer
88972
+ kit,
88973
+ wallet
90156
88974
  };
90157
88975
  }
90158
88976
  async function startStdio() {
90159
88977
  log("Starting in stdio mode...");
90160
- log(`Network: ${NETWORK}`);
90161
- const { server, signer } = createAdaptersAndServer();
88978
+ const { server, kit } = await createWalletAndServer();
90162
88979
  const transport = new StdioServerTransport();
90163
88980
  const shutdown = async () => {
90164
88981
  log("Shutting down...");
90165
- await signer.close();
88982
+ await kit.close();
90166
88983
  log("Shutdown complete");
90167
88984
  process.exit(0);
90168
88985
  };
@@ -90171,32 +88988,31 @@ async function startStdio() {
90171
88988
  await server.connect(transport);
90172
88989
  log("Server connected and ready to accept requests");
90173
88990
  }
90174
- async function startHttp(port) {
90175
- log(`Starting in HTTP mode on port ${port}...`);
90176
- log(`Network: ${NETWORK}`);
90177
- const { server, signer } = createAdaptersAndServer();
88991
+ async function startHttp(port, host) {
88992
+ log(`Starting in HTTP mode on ${host}:${port}...`);
88993
+ const { server, kit } = await createWalletAndServer();
90178
88994
  const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() });
90179
88995
  await server.connect(transport);
90180
88996
  const httpServer = createServer(async (req, res) => {
90181
- if (new URL(req.url ?? "/", `http://localhost:${port}`).pathname === "/mcp") await transport.handleRequest(req, res);
88997
+ if (new URL(req.url ?? "/", `http://${host}:${port}`).pathname === "/mcp") await transport.handleRequest(req, res);
90182
88998
  else res.writeHead(404).end("Not Found");
90183
88999
  });
90184
89000
  const shutdown = async () => {
90185
89001
  log("Shutting down...");
90186
89002
  httpServer.close();
90187
89003
  await transport.close();
90188
- await signer.close();
89004
+ await kit.close();
90189
89005
  log("Shutdown complete");
90190
89006
  process.exit(0);
90191
89007
  };
90192
89008
  process.on("SIGINT", shutdown);
90193
89009
  process.on("SIGTERM", shutdown);
90194
- httpServer.listen(port, () => {
90195
- log(`HTTP server listening on http://localhost:${port}/mcp`);
89010
+ httpServer.listen(port, host, () => {
89011
+ log(`HTTP server listening on http://${host}:${port}/mcp`);
90196
89012
  });
90197
89013
  }
90198
89014
  const config = parseArgs();
90199
- if (config.mode === "http") startHttp(config.port).catch((error) => {
89015
+ if (config.mode === "http") startHttp(config.port, config.host).catch((error) => {
90200
89016
  console.error(`[${SERVER_NAME}] Fatal error:`, error);
90201
89017
  process.exit(1);
90202
89018
  });